audio: second batch of -audiodev support, adding support for multiple backends.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJdXQOFAAoJEEy22O7T6HE4/DIP+QGVIPrhnqdP4ZIG6FHMlgUO DS5lmd5TyHXLNBSTYn4dZfQ+V0fMmYrDe9xEMujKrRHJ0/rxhapPymvf0hniRevw WlcKKMQdW+cIW144ujk1T2ELjJdy/CqDnfb8rMr/CAeFW0qXSTjE8M178Ii1M6gd CI+3Rkt8VgmCXYR2b9xAX0bEs0ncjxTAlBSxEFpiA5ZpX1WvWxPQont7zzvANQb/ l33WmD1UTymZT9vtFIOL6GsN4/kk4pY8+n42LkLGPyQ1iZuxFH0AmsXIPcKQvOV+ w4qn/Kcrhvx8stYw7laPjuPzYzWSbHcC1CsoShbfdFpPw4Sp9rxKT8t1aiB/aeiP M4lbyHn3ZqwclWLFd7l8sTgIbe4OtYfhIWOx6f0cpdUxH8Qwkh/ij+c+yEYD3Kt3 AMjtigQ29ixXquVNVjhlV770mmnaZ29ONtPTBq6Fwt+A9ksGtdNLs3SZmzoFkKPe 0ByviDWhPdsjw7dRz/Pz5yZOgJHbJHvmkrCuQkKlJByOlUIgd4kVqVCZ9ZRaaBEw upw0g8QFStVmf7wGfflMT6sTGIXUSTAmxoWVWi8o+qFmV1uKtSpZU4pWa1IGMX/j T97/Uosee3vGFgcU1Ea0hnDpzNHUQTYMqJHVkg30avQnLh8WYkly6eo9yyQkVj+8 9Oi+J3H/6vjUeTtP66f2 =KtI3 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/audio-20190821-pull-request' into staging audio: second batch of -audiodev support, adding support for multiple backends. # gpg: Signature made Wed 21 Aug 2019 09:40:37 BST # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/audio-20190821-pull-request: audio: fix memory leak reported by ASAN audio: use size_t where makes sense audio: remove read and write pcm_ops paaudio: fix playback glitches audio: do not run each backend in audio_run audio: remove audio_MIN, audio_MAX paaudio: properly disconnect streams in fini_* paaudio: do not move stream when sink/source name is specified audio: audiodev= parameters no longer optional when -audiodev present paaudio: prepare for multiple audiodev audio: add audiodev properties to frontends audio: add audiodev property to vnc and wav_capture audio: basic support for multi backend audio audio: reduce glob_audio_state usage audio: Add missing fall through comments Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
33f18cf7dc
@ -39,6 +39,7 @@ struct pollhlp {
|
||||
struct pollfd *pfds;
|
||||
int count;
|
||||
int mask;
|
||||
AudioState *s;
|
||||
};
|
||||
|
||||
typedef struct ALSAVoiceOut {
|
||||
@ -199,11 +200,11 @@ static void alsa_poll_handler (void *opaque)
|
||||
break;
|
||||
|
||||
case SND_PCM_STATE_PREPARED:
|
||||
audio_run ("alsa run (prepared)");
|
||||
audio_run(hlp->s, "alsa run (prepared)");
|
||||
break;
|
||||
|
||||
case SND_PCM_STATE_RUNNING:
|
||||
audio_run ("alsa run (running)");
|
||||
audio_run(hlp->s, "alsa run (running)");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -269,11 +270,6 @@ static int alsa_poll_in (HWVoiceIn *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);
|
||||
}
|
||||
|
||||
static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
|
||||
{
|
||||
switch (fmt) {
|
||||
@ -634,7 +630,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
|
||||
|
||||
while (alsa->pending) {
|
||||
int left_till_end_samples = hw->samples - alsa->wpos;
|
||||
int len = audio_MIN (alsa->pending, left_till_end_samples);
|
||||
int len = MIN (alsa->pending, left_till_end_samples);
|
||||
char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
|
||||
|
||||
while (len) {
|
||||
@ -685,10 +681,10 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
|
||||
}
|
||||
}
|
||||
|
||||
static int alsa_run_out (HWVoiceOut *hw, int live)
|
||||
static size_t alsa_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
|
||||
int decr;
|
||||
size_t decr;
|
||||
snd_pcm_sframes_t avail;
|
||||
|
||||
avail = alsa_get_avail (alsa->handle);
|
||||
@ -697,7 +693,7 @@ static int alsa_run_out (HWVoiceOut *hw, int live)
|
||||
return 0;
|
||||
}
|
||||
|
||||
decr = audio_MIN (live, avail);
|
||||
decr = MIN (live, avail);
|
||||
decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
|
||||
alsa->pending += decr;
|
||||
alsa_write_pending (alsa);
|
||||
@ -743,12 +739,13 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
|
||||
alsa->pcm_buf = audio_calloc(__func__, obt.samples, 1 << hw->info.shift);
|
||||
if (!alsa->pcm_buf) {
|
||||
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
dolog("Could not allocate DAC buffer (%zu samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
alsa_anal_close1 (&handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
alsa->pollhlp.s = hw->s;
|
||||
alsa->handle = handle;
|
||||
alsa->dev = dev;
|
||||
return 0;
|
||||
@ -844,12 +841,13 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
|
||||
alsa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
if (!alsa->pcm_buf) {
|
||||
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
dolog("Could not allocate ADC buffer (%zu samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
alsa_anal_close1 (&handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
alsa->pollhlp.s = hw->s;
|
||||
alsa->handle = handle;
|
||||
alsa->dev = dev;
|
||||
return 0;
|
||||
@ -865,17 +863,17 @@ static void alsa_fini_in (HWVoiceIn *hw)
|
||||
alsa->pcm_buf = NULL;
|
||||
}
|
||||
|
||||
static int alsa_run_in (HWVoiceIn *hw)
|
||||
static size_t alsa_run_in(HWVoiceIn *hw)
|
||||
{
|
||||
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
||||
int hwshift = hw->info.shift;
|
||||
int i;
|
||||
int live = audio_pcm_hw_get_live_in (hw);
|
||||
int dead = hw->samples - live;
|
||||
int decr;
|
||||
size_t live = audio_pcm_hw_get_live_in (hw);
|
||||
size_t dead = hw->samples - live;
|
||||
size_t decr;
|
||||
struct {
|
||||
int add;
|
||||
int len;
|
||||
size_t add;
|
||||
size_t len;
|
||||
} bufs[2] = {
|
||||
{ .add = hw->wpos, .len = 0 },
|
||||
{ .add = 0, .len = 0 }
|
||||
@ -915,7 +913,7 @@ static int alsa_run_in (HWVoiceIn *hw)
|
||||
}
|
||||
}
|
||||
|
||||
decr = audio_MIN (dead, avail);
|
||||
decr = MIN(dead, avail);
|
||||
if (!decr) {
|
||||
return 0;
|
||||
}
|
||||
@ -985,11 +983,6 @@ static int alsa_run_in (HWVoiceIn *hw)
|
||||
return read_samples;
|
||||
}
|
||||
|
||||
static int alsa_read (SWVoiceIn *sw, void *buf, int size)
|
||||
{
|
||||
return audio_pcm_sw_read (sw, buf, size);
|
||||
}
|
||||
|
||||
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||
{
|
||||
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
||||
@ -1073,13 +1066,11 @@ static struct audio_pcm_ops alsa_pcm_ops = {
|
||||
.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,
|
||||
};
|
||||
|
||||
|
347
audio/audio.c
347
audio/audio.c
@ -87,7 +87,8 @@ audio_driver *audio_driver_lookup(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static AudioState glob_audio_state;
|
||||
static QTAILQ_HEAD(AudioStateHead, AudioState) audio_states =
|
||||
QTAILQ_HEAD_INITIALIZER(audio_states);
|
||||
|
||||
const struct mixeng_volume nominal_volume = {
|
||||
.mute = 0,
|
||||
@ -100,6 +101,8 @@ const struct mixeng_volume nominal_volume = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool legacy_config = true;
|
||||
|
||||
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
|
||||
#error No its not
|
||||
#else
|
||||
@ -306,6 +309,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
||||
|
||||
case AUDIO_FORMAT_S16:
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U16:
|
||||
bits = 16;
|
||||
shift = 1;
|
||||
@ -313,6 +317,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
||||
|
||||
case AUDIO_FORMAT_S32:
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U32:
|
||||
bits = 32;
|
||||
shift = 2;
|
||||
@ -399,12 +404,10 @@ static void noop_conv (struct st_sample *dst, const void *src, int samples)
|
||||
(void) samples;
|
||||
}
|
||||
|
||||
static CaptureVoiceOut *audio_pcm_capture_find_specific (
|
||||
struct audsettings *as
|
||||
)
|
||||
static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
|
||||
struct audsettings *as)
|
||||
{
|
||||
CaptureVoiceOut *cap;
|
||||
AudioState *s = &glob_audio_state;
|
||||
|
||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||
if (audio_pcm_info_eq (&cap->hw.info, as)) {
|
||||
@ -481,7 +484,7 @@ static void audio_detach_capture (HWVoiceOut *hw)
|
||||
|
||||
static int audio_attach_capture (HWVoiceOut *hw)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
AudioState *s = hw->s;
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
audio_detach_capture (hw);
|
||||
@ -525,41 +528,41 @@ static int audio_attach_capture (HWVoiceOut *hw)
|
||||
/*
|
||||
* Hard voice (capture)
|
||||
*/
|
||||
static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
|
||||
static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
|
||||
{
|
||||
SWVoiceIn *sw;
|
||||
int m = hw->total_samples_captured;
|
||||
size_t m = hw->total_samples_captured;
|
||||
|
||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||
if (sw->active) {
|
||||
m = audio_MIN (m, sw->total_hw_samples_acquired);
|
||||
m = MIN (m, sw->total_hw_samples_acquired);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
|
||||
size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
||||
{
|
||||
int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
||||
if (audio_bug(__func__, live > hw->samples)) {
|
||||
dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
return live;
|
||||
}
|
||||
|
||||
int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
|
||||
int live, int pending)
|
||||
size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
|
||||
size_t live, size_t pending)
|
||||
{
|
||||
int left = hw->samples - pending;
|
||||
int len = audio_MIN (left, live);
|
||||
int clipped = 0;
|
||||
size_t left = hw->samples - pending;
|
||||
size_t len = MIN (left, live);
|
||||
size_t clipped = 0;
|
||||
|
||||
while (len) {
|
||||
struct st_sample *src = hw->mix_buf + hw->rpos;
|
||||
uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
|
||||
int samples_till_end_of_buf = hw->samples - hw->rpos;
|
||||
int samples_to_clip = audio_MIN (len, samples_till_end_of_buf);
|
||||
size_t samples_till_end_of_buf = hw->samples - hw->rpos;
|
||||
size_t samples_to_clip = MIN (len, samples_till_end_of_buf);
|
||||
|
||||
hw->clip (dst, src, samples_to_clip);
|
||||
|
||||
@ -573,14 +576,14 @@ int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
|
||||
/*
|
||||
* Soft voice (capture)
|
||||
*/
|
||||
static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
|
||||
static size_t audio_pcm_sw_get_rpos_in(SWVoiceIn *sw)
|
||||
{
|
||||
HWVoiceIn *hw = sw->hw;
|
||||
int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
int rpos;
|
||||
ssize_t live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
ssize_t rpos;
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -593,17 +596,17 @@ static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
|
||||
}
|
||||
}
|
||||
|
||||
int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
||||
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||
{
|
||||
HWVoiceIn *hw = sw->hw;
|
||||
int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
||||
size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
||||
struct st_sample *src, *dst = sw->buf;
|
||||
|
||||
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
|
||||
|
||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
|
||||
if (audio_bug(__func__, live > hw->samples)) {
|
||||
dolog("live_in=%zu hw->samples=%zu\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -613,13 +616,13 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
||||
}
|
||||
|
||||
swlim = (live * sw->ratio) >> 32;
|
||||
swlim = audio_MIN (swlim, samples);
|
||||
swlim = MIN (swlim, samples);
|
||||
|
||||
while (swlim) {
|
||||
src = hw->conv_buf + rpos;
|
||||
isamp = hw->wpos - rpos;
|
||||
/* XXX: <= ? */
|
||||
if (isamp <= 0) {
|
||||
if (hw->wpos > rpos) {
|
||||
isamp = hw->wpos - rpos;
|
||||
} else {
|
||||
isamp = hw->samples - rpos;
|
||||
}
|
||||
|
||||
@ -628,11 +631,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
||||
}
|
||||
osamp = swlim;
|
||||
|
||||
if (audio_bug(__func__, osamp < 0)) {
|
||||
dolog ("osamp=%d\n", osamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
|
||||
swlim -= osamp;
|
||||
rpos = (rpos + isamp) % hw->samples;
|
||||
@ -653,15 +651,15 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
||||
/*
|
||||
* Hard voice (playback)
|
||||
*/
|
||||
static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
|
||||
static size_t audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
|
||||
{
|
||||
SWVoiceOut *sw;
|
||||
int m = INT_MAX;
|
||||
size_t m = SIZE_MAX;
|
||||
int nb_live = 0;
|
||||
|
||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||
if (sw->active || !sw->empty) {
|
||||
m = audio_MIN (m, sw->total_hw_samples_mixed);
|
||||
m = MIN (m, sw->total_hw_samples_mixed);
|
||||
nb_live += 1;
|
||||
}
|
||||
}
|
||||
@ -670,9 +668,9 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
|
||||
return m;
|
||||
}
|
||||
|
||||
static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
||||
static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
||||
{
|
||||
int smin;
|
||||
size_t smin;
|
||||
int nb_live1;
|
||||
|
||||
smin = audio_pcm_hw_find_min_out (hw, &nb_live1);
|
||||
@ -681,10 +679,10 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
||||
}
|
||||
|
||||
if (nb_live1) {
|
||||
int live = smin;
|
||||
size_t live = smin;
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
if (audio_bug(__func__, live > hw->samples)) {
|
||||
dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
|
||||
return 0;
|
||||
}
|
||||
return live;
|
||||
@ -695,10 +693,10 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
||||
/*
|
||||
* Soft voice (playback)
|
||||
*/
|
||||
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||
{
|
||||
int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
|
||||
int ret = 0, pos = 0, total = 0;
|
||||
size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
|
||||
size_t ret = 0, pos = 0, total = 0;
|
||||
|
||||
if (!sw) {
|
||||
return size;
|
||||
@ -707,8 +705,8 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
hwsamples = sw->hw->samples;
|
||||
|
||||
live = sw->total_hw_samples_mixed;
|
||||
if (audio_bug(__func__, live < 0 || live > hwsamples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hwsamples);
|
||||
if (audio_bug(__func__, live > hwsamples)) {
|
||||
dolog("live=%zu hw->samples=%zu\n", live, hwsamples);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -724,7 +722,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
|
||||
dead = hwsamples - live;
|
||||
swlim = ((int64_t) dead << 32) / sw->ratio;
|
||||
swlim = audio_MIN (swlim, samples);
|
||||
swlim = MIN (swlim, samples);
|
||||
if (swlim) {
|
||||
sw->conv (sw->buf, buf, swlim);
|
||||
|
||||
@ -736,7 +734,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
while (swlim) {
|
||||
dead = hwsamples - live;
|
||||
left = hwsamples - wpos;
|
||||
blck = audio_MIN (dead, left);
|
||||
blck = MIN (dead, left);
|
||||
if (!blck) {
|
||||
break;
|
||||
}
|
||||
@ -762,7 +760,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
|
||||
#ifdef DEBUG_OUT
|
||||
dolog (
|
||||
"%s: write size %d ret %d total sw %d\n",
|
||||
"%s: write size %zu ret %zu total sw %zu\n",
|
||||
SW_NAME (sw),
|
||||
size >> sw->info.shift,
|
||||
ret,
|
||||
@ -789,19 +787,15 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
|
||||
/*
|
||||
* Timer
|
||||
*/
|
||||
|
||||
static bool audio_timer_running;
|
||||
static uint64_t audio_timer_last;
|
||||
|
||||
static int audio_is_timer_needed (void)
|
||||
static int audio_is_timer_needed(AudioState *s)
|
||||
{
|
||||
HWVoiceIn *hwi = NULL;
|
||||
HWVoiceOut *hwo = NULL;
|
||||
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out(s, hwo))) {
|
||||
if (!hwo->poll_mode) return 1;
|
||||
}
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in(s, hwi))) {
|
||||
if (!hwi->poll_mode) return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -809,18 +803,18 @@ static int audio_is_timer_needed (void)
|
||||
|
||||
static void audio_reset_timer (AudioState *s)
|
||||
{
|
||||
if (audio_is_timer_needed ()) {
|
||||
if (audio_is_timer_needed(s)) {
|
||||
timer_mod_anticipate_ns(s->ts,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->period_ticks);
|
||||
if (!audio_timer_running) {
|
||||
audio_timer_running = true;
|
||||
audio_timer_last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (!s->timer_running) {
|
||||
s->timer_running = true;
|
||||
s->timer_last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
trace_audio_timer_start(s->period_ticks / SCALE_MS);
|
||||
}
|
||||
} else {
|
||||
timer_del(s->ts);
|
||||
if (audio_timer_running) {
|
||||
audio_timer_running = false;
|
||||
if (s->timer_running) {
|
||||
s->timer_running = false;
|
||||
trace_audio_timer_stop();
|
||||
}
|
||||
}
|
||||
@ -832,20 +826,20 @@ static void audio_timer (void *opaque)
|
||||
AudioState *s = opaque;
|
||||
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
diff = now - audio_timer_last;
|
||||
diff = now - s->timer_last;
|
||||
if (diff > s->period_ticks * 3 / 2) {
|
||||
trace_audio_timer_delayed(diff / SCALE_MS);
|
||||
}
|
||||
audio_timer_last = now;
|
||||
s->timer_last = now;
|
||||
|
||||
audio_run("timer");
|
||||
audio_run(s, "timer");
|
||||
audio_reset_timer(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public API
|
||||
*/
|
||||
int AUD_write (SWVoiceOut *sw, void *buf, int size)
|
||||
size_t AUD_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||
{
|
||||
if (!sw) {
|
||||
/* XXX: Consider options */
|
||||
@ -857,10 +851,10 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sw->hw->pcm_ops->write(sw, buf, size);
|
||||
return audio_pcm_sw_write(sw, buf, size);
|
||||
}
|
||||
|
||||
int AUD_read (SWVoiceIn *sw, void *buf, int size)
|
||||
size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||
{
|
||||
if (!sw) {
|
||||
/* XXX: Consider options */
|
||||
@ -872,7 +866,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sw->hw->pcm_ops->read(sw, buf, size);
|
||||
return audio_pcm_sw_read(sw, buf, size);
|
||||
}
|
||||
|
||||
int AUD_get_buffer_size_out (SWVoiceOut *sw)
|
||||
@ -890,7 +884,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||
|
||||
hw = sw->hw;
|
||||
if (sw->active != on) {
|
||||
AudioState *s = &glob_audio_state;
|
||||
AudioState *s = sw->s;
|
||||
SWVoiceOut *temp_sw;
|
||||
SWVoiceCap *sc;
|
||||
|
||||
@ -937,7 +931,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
|
||||
|
||||
hw = sw->hw;
|
||||
if (sw->active != on) {
|
||||
AudioState *s = &glob_audio_state;
|
||||
AudioState *s = sw->s;
|
||||
SWVoiceIn *temp_sw;
|
||||
|
||||
if (on) {
|
||||
@ -969,17 +963,17 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
|
||||
}
|
||||
}
|
||||
|
||||
static int audio_get_avail (SWVoiceIn *sw)
|
||||
static size_t audio_get_avail (SWVoiceIn *sw)
|
||||
{
|
||||
int live;
|
||||
size_t live;
|
||||
|
||||
if (!sw) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
|
||||
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
|
||||
if (audio_bug(__func__, live > sw->hw->samples)) {
|
||||
dolog("live=%zu sw->hw->samples=%zu\n", live, sw->hw->samples);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -992,9 +986,9 @@ static int audio_get_avail (SWVoiceIn *sw)
|
||||
return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
|
||||
}
|
||||
|
||||
static int audio_get_free (SWVoiceOut *sw)
|
||||
static size_t audio_get_free(SWVoiceOut *sw)
|
||||
{
|
||||
int live, dead;
|
||||
size_t live, dead;
|
||||
|
||||
if (!sw) {
|
||||
return 0;
|
||||
@ -1002,8 +996,8 @@ static int audio_get_free (SWVoiceOut *sw)
|
||||
|
||||
live = sw->total_hw_samples_mixed;
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
|
||||
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
|
||||
if (audio_bug(__func__, live > sw->hw->samples)) {
|
||||
dolog("live=%zu sw->hw->samples=%zu\n", live, sw->hw->samples);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1018,9 +1012,10 @@ static int audio_get_free (SWVoiceOut *sw)
|
||||
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
|
||||
}
|
||||
|
||||
static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
|
||||
static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
|
||||
size_t samples)
|
||||
{
|
||||
int n;
|
||||
size_t n;
|
||||
|
||||
if (hw->enabled) {
|
||||
SWVoiceCap *sc;
|
||||
@ -1031,17 +1026,17 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
|
||||
|
||||
n = samples;
|
||||
while (n) {
|
||||
int till_end_of_hw = hw->samples - rpos2;
|
||||
int to_write = audio_MIN (till_end_of_hw, n);
|
||||
int bytes = to_write << hw->info.shift;
|
||||
int written;
|
||||
size_t till_end_of_hw = hw->samples - rpos2;
|
||||
size_t to_write = MIN(till_end_of_hw, n);
|
||||
size_t bytes = to_write << hw->info.shift;
|
||||
size_t written;
|
||||
|
||||
sw->buf = hw->mix_buf + rpos2;
|
||||
written = audio_pcm_sw_write (sw, NULL, bytes);
|
||||
if (written - bytes) {
|
||||
dolog ("Could not mix %d bytes into a capture "
|
||||
"buffer, mixed %d\n",
|
||||
bytes, written);
|
||||
dolog("Could not mix %zu bytes into a capture "
|
||||
"buffer, mixed %zu\n",
|
||||
bytes, written);
|
||||
break;
|
||||
}
|
||||
n -= to_write;
|
||||
@ -1050,9 +1045,9 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
|
||||
}
|
||||
}
|
||||
|
||||
n = audio_MIN (samples, hw->samples - rpos);
|
||||
mixeng_clear (hw->mix_buf + rpos, n);
|
||||
mixeng_clear (hw->mix_buf, samples - n);
|
||||
n = MIN(samples, hw->samples - rpos);
|
||||
mixeng_clear(hw->mix_buf + rpos, n);
|
||||
mixeng_clear(hw->mix_buf, samples - n);
|
||||
}
|
||||
|
||||
static void audio_run_out (AudioState *s)
|
||||
@ -1060,17 +1055,17 @@ static void audio_run_out (AudioState *s)
|
||||
HWVoiceOut *hw = NULL;
|
||||
SWVoiceOut *sw;
|
||||
|
||||
while ((hw = audio_pcm_hw_find_any_enabled_out (hw))) {
|
||||
int played;
|
||||
int live, free, nb_live, cleanup_required, prev_rpos;
|
||||
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
|
||||
size_t played, live, prev_rpos, free;
|
||||
int nb_live, cleanup_required;
|
||||
|
||||
live = audio_pcm_hw_get_live_out (hw, &nb_live);
|
||||
if (!nb_live) {
|
||||
live = 0;
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
||||
if (audio_bug(__func__, live > hw->samples)) {
|
||||
dolog ("live=%zu hw->samples=%zu\n", live, hw->samples);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1105,13 +1100,13 @@ static void audio_run_out (AudioState *s)
|
||||
played = hw->pcm_ops->run_out (hw, live);
|
||||
replay_audio_out(&played);
|
||||
if (audio_bug(__func__, hw->rpos >= hw->samples)) {
|
||||
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
|
||||
hw->rpos, hw->samples, played);
|
||||
dolog("hw->rpos=%zu hw->samples=%zu played=%zu\n",
|
||||
hw->rpos, hw->samples, played);
|
||||
hw->rpos = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_OUT
|
||||
dolog ("played=%d\n", played);
|
||||
dolog("played=%zu\n", played);
|
||||
#endif
|
||||
|
||||
if (played) {
|
||||
@ -1126,8 +1121,8 @@ static void audio_run_out (AudioState *s)
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) {
|
||||
dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
|
||||
played, sw->total_hw_samples_mixed);
|
||||
dolog("played=%zu sw->total_hw_samples_mixed=%zu\n",
|
||||
played, sw->total_hw_samples_mixed);
|
||||
played = sw->total_hw_samples_mixed;
|
||||
}
|
||||
|
||||
@ -1165,9 +1160,9 @@ static void audio_run_in (AudioState *s)
|
||||
{
|
||||
HWVoiceIn *hw = NULL;
|
||||
|
||||
while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) {
|
||||
while ((hw = audio_pcm_hw_find_any_enabled_in(s, hw))) {
|
||||
SWVoiceIn *sw;
|
||||
int captured = 0, min;
|
||||
size_t captured = 0, min;
|
||||
|
||||
if (replay_mode != REPLAY_MODE_PLAY) {
|
||||
captured = hw->pcm_ops->run_in(hw);
|
||||
@ -1182,7 +1177,7 @@ static void audio_run_in (AudioState *s)
|
||||
sw->total_hw_samples_acquired -= min;
|
||||
|
||||
if (sw->active) {
|
||||
int avail;
|
||||
size_t avail;
|
||||
|
||||
avail = audio_get_avail (sw);
|
||||
if (avail > 0) {
|
||||
@ -1198,15 +1193,15 @@ static void audio_run_capture (AudioState *s)
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||
int live, rpos, captured;
|
||||
size_t live, rpos, captured;
|
||||
HWVoiceOut *hw = &cap->hw;
|
||||
SWVoiceOut *sw;
|
||||
|
||||
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
|
||||
rpos = hw->rpos;
|
||||
while (live) {
|
||||
int left = hw->samples - rpos;
|
||||
int to_capture = audio_MIN (live, left);
|
||||
size_t left = hw->samples - rpos;
|
||||
size_t to_capture = MIN(live, left);
|
||||
struct st_sample *src;
|
||||
struct capture_callback *cb;
|
||||
|
||||
@ -1229,8 +1224,8 @@ static void audio_run_capture (AudioState *s)
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) {
|
||||
dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
|
||||
captured, sw->total_hw_samples_mixed);
|
||||
dolog("captured=%zu sw->total_hw_samples_mixed=%zu\n",
|
||||
captured, sw->total_hw_samples_mixed);
|
||||
captured = sw->total_hw_samples_mixed;
|
||||
}
|
||||
|
||||
@ -1240,13 +1235,12 @@ static void audio_run_capture (AudioState *s)
|
||||
}
|
||||
}
|
||||
|
||||
void audio_run (const char *msg)
|
||||
void audio_run(AudioState *s, const char *msg)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
audio_run_out(s);
|
||||
audio_run_in(s);
|
||||
audio_run_capture(s);
|
||||
|
||||
audio_run_out (s);
|
||||
audio_run_in (s);
|
||||
audio_run_capture (s);
|
||||
#ifdef DEBUG_POLL
|
||||
{
|
||||
static double prevtime;
|
||||
@ -1271,8 +1265,8 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv,
|
||||
s->drv_opaque = drv->init(dev);
|
||||
|
||||
if (s->drv_opaque) {
|
||||
audio_init_nb_voices_out (drv);
|
||||
audio_init_nb_voices_in (drv);
|
||||
audio_init_nb_voices_out(s, drv);
|
||||
audio_init_nb_voices_in(s, drv);
|
||||
s->drv = drv;
|
||||
return 0;
|
||||
}
|
||||
@ -1293,11 +1287,11 @@ static void audio_vm_change_state_handler (void *opaque, int running,
|
||||
int op = running ? VOICE_ENABLE : VOICE_DISABLE;
|
||||
|
||||
s->vm_running = running;
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out(s, hwo))) {
|
||||
hwo->pcm_ops->ctl_out(hwo, op);
|
||||
}
|
||||
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in(s, hwi))) {
|
||||
hwi->pcm_ops->ctl_in(hwi, op);
|
||||
}
|
||||
audio_reset_timer (s);
|
||||
@ -1310,14 +1304,12 @@ bool audio_is_cleaning_up(void)
|
||||
return is_cleaning_up;
|
||||
}
|
||||
|
||||
void audio_cleanup(void)
|
||||
static void free_audio_state(AudioState *s)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
HWVoiceOut *hwo, *hwon;
|
||||
HWVoiceIn *hwi, *hwin;
|
||||
|
||||
is_cleaning_up = true;
|
||||
QLIST_FOREACH_SAFE(hwo, &glob_audio_state.hw_head_out, entries, hwon) {
|
||||
QLIST_FOREACH_SAFE(hwo, &s->hw_head_out, entries, hwon) {
|
||||
SWVoiceCap *sc;
|
||||
|
||||
if (hwo->enabled) {
|
||||
@ -1336,7 +1328,7 @@ void audio_cleanup(void)
|
||||
QLIST_REMOVE(hwo, entries);
|
||||
}
|
||||
|
||||
QLIST_FOREACH_SAFE(hwi, &glob_audio_state.hw_head_in, entries, hwin) {
|
||||
QLIST_FOREACH_SAFE(hwi, &s->hw_head_in, entries, hwin) {
|
||||
if (hwi->enabled) {
|
||||
hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
|
||||
}
|
||||
@ -1353,6 +1345,23 @@ void audio_cleanup(void)
|
||||
qapi_free_Audiodev(s->dev);
|
||||
s->dev = NULL;
|
||||
}
|
||||
|
||||
if (s->ts) {
|
||||
timer_free(s->ts);
|
||||
s->ts = NULL;
|
||||
}
|
||||
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
void audio_cleanup(void)
|
||||
{
|
||||
is_cleaning_up = true;
|
||||
while (!QTAILQ_EMPTY(&audio_states)) {
|
||||
AudioState *s = QTAILQ_FIRST(&audio_states);
|
||||
QTAILQ_REMOVE(&audio_states, s, list);
|
||||
free_audio_state(s);
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_audio = {
|
||||
@ -1379,28 +1388,34 @@ static AudiodevListEntry *audiodev_find(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int audio_init(Audiodev *dev)
|
||||
/*
|
||||
* if we have dev, this function was called because of an -audiodev argument =>
|
||||
* initialize a new state with it
|
||||
* if dev == NULL => legacy implicit initialization, return the already created
|
||||
* state or create a new one
|
||||
*/
|
||||
static AudioState *audio_init(Audiodev *dev, const char *name)
|
||||
{
|
||||
static bool atexit_registered;
|
||||
size_t i;
|
||||
int done = 0;
|
||||
const char *drvname = NULL;
|
||||
VMChangeStateEntry *e;
|
||||
AudioState *s = &glob_audio_state;
|
||||
AudioState *s;
|
||||
struct audio_driver *driver;
|
||||
/* silence gcc warning about uninitialized variable */
|
||||
AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
|
||||
|
||||
if (s->drv) {
|
||||
if (dev) {
|
||||
dolog("Cannot create more than one audio backend, sorry\n");
|
||||
qapi_free_Audiodev(dev);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
/* -audiodev option */
|
||||
legacy_config = false;
|
||||
drvname = AudiodevDriver_str(dev->driver);
|
||||
} else if (!QTAILQ_EMPTY(&audio_states)) {
|
||||
if (!legacy_config) {
|
||||
dolog("You must specify an audiodev= for the device %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
return QTAILQ_FIRST(&audio_states);
|
||||
} else {
|
||||
/* legacy implicit initialization */
|
||||
head = audio_handle_legacy_opts();
|
||||
@ -1414,12 +1429,18 @@ static int audio_init(Audiodev *dev)
|
||||
dev = QSIMPLEQ_FIRST(&head)->dev;
|
||||
audio_validate_opts(dev, &error_abort);
|
||||
}
|
||||
|
||||
s = g_malloc0(sizeof(AudioState));
|
||||
s->dev = dev;
|
||||
|
||||
QLIST_INIT (&s->hw_head_out);
|
||||
QLIST_INIT (&s->hw_head_in);
|
||||
QLIST_INIT (&s->cap_head);
|
||||
atexit(audio_cleanup);
|
||||
if (!atexit_registered) {
|
||||
atexit(audio_cleanup);
|
||||
atexit_registered = true;
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&audio_states, s, list);
|
||||
|
||||
s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);
|
||||
|
||||
@ -1484,7 +1505,7 @@ static int audio_init(Audiodev *dev)
|
||||
|
||||
QLIST_INIT (&s->card_head);
|
||||
vmstate_register (NULL, 0, &vmstate_audio, s);
|
||||
return 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
void audio_free_audiodev_list(AudiodevListHead *head)
|
||||
@ -1499,10 +1520,13 @@ void audio_free_audiodev_list(AudiodevListHead *head)
|
||||
|
||||
void AUD_register_card (const char *name, QEMUSoundCard *card)
|
||||
{
|
||||
audio_init(NULL);
|
||||
if (!card->state) {
|
||||
card->state = audio_init(NULL, name);
|
||||
}
|
||||
|
||||
card->name = g_strdup (name);
|
||||
memset (&card->entries, 0, sizeof (card->entries));
|
||||
QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
|
||||
QLIST_INSERT_HEAD(&card->state->card_head, card, entries);
|
||||
}
|
||||
|
||||
void AUD_remove_card (QEMUSoundCard *card)
|
||||
@ -1512,16 +1536,24 @@ void AUD_remove_card (QEMUSoundCard *card)
|
||||
}
|
||||
|
||||
|
||||
CaptureVoiceOut *AUD_add_capture (
|
||||
CaptureVoiceOut *AUD_add_capture(
|
||||
AudioState *s,
|
||||
struct audsettings *as,
|
||||
struct audio_capture_ops *ops,
|
||||
void *cb_opaque
|
||||
)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
CaptureVoiceOut *cap;
|
||||
struct capture_callback *cb;
|
||||
|
||||
if (!s) {
|
||||
if (!legacy_config) {
|
||||
dolog("You must specify audiodev when trying to capture\n");
|
||||
return NULL;
|
||||
}
|
||||
s = audio_init(NULL, NULL);
|
||||
}
|
||||
|
||||
if (audio_validate_settings (as)) {
|
||||
dolog ("Invalid settings were passed when trying to add capture\n");
|
||||
audio_print_settings (as);
|
||||
@ -1532,7 +1564,7 @@ CaptureVoiceOut *AUD_add_capture (
|
||||
cb->ops = *ops;
|
||||
cb->opaque = cb_opaque;
|
||||
|
||||
cap = audio_pcm_capture_find_specific (as);
|
||||
cap = audio_pcm_capture_find_specific(s, as);
|
||||
if (cap) {
|
||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||
return cap;
|
||||
@ -1544,6 +1576,7 @@ CaptureVoiceOut *AUD_add_capture (
|
||||
cap = g_malloc0(sizeof(*cap));
|
||||
|
||||
hw = &cap->hw;
|
||||
hw->s = s;
|
||||
QLIST_INIT (&hw->sw_head);
|
||||
QLIST_INIT (&cap->cb_head);
|
||||
|
||||
@ -1564,7 +1597,7 @@ CaptureVoiceOut *AUD_add_capture (
|
||||
QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||
|
||||
QLIST_FOREACH(hw, &glob_audio_state.hw_head_out, entries) {
|
||||
QLIST_FOREACH(hw, &s->hw_head_out, entries) {
|
||||
audio_attach_capture (hw);
|
||||
}
|
||||
return cap;
|
||||
@ -1749,7 +1782,7 @@ void audio_init_audiodevs(void)
|
||||
AudiodevListEntry *e;
|
||||
|
||||
QSIMPLEQ_FOREACH(e, &audiodevs, next) {
|
||||
audio_init(e->dev);
|
||||
audio_init(e->dev, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1810,3 +1843,25 @@ int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo,
|
||||
return audio_buffer_samples(pdo, as, def_usecs) *
|
||||
audioformat_bytes_per_sample(as->fmt);
|
||||
}
|
||||
|
||||
AudioState *audio_state_by_name(const char *name)
|
||||
{
|
||||
AudioState *s;
|
||||
QTAILQ_FOREACH(s, &audio_states, list) {
|
||||
assert(s->dev);
|
||||
if (strcmp(name, s->dev->id) == 0) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *audio_get_id(QEMUSoundCard *card)
|
||||
{
|
||||
if (card->state) {
|
||||
assert(card->state->dev);
|
||||
return card->state->dev->id;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "qemu/queue.h"
|
||||
#include "qapi/qapi-types-audio.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
||||
typedef void (*audio_callback_fn) (void *opaque, int avail);
|
||||
|
||||
@ -78,8 +79,10 @@ typedef struct SWVoiceOut SWVoiceOut;
|
||||
typedef struct CaptureVoiceOut CaptureVoiceOut;
|
||||
typedef struct SWVoiceIn SWVoiceIn;
|
||||
|
||||
typedef struct AudioState AudioState;
|
||||
typedef struct QEMUSoundCard {
|
||||
char *name;
|
||||
AudioState *state;
|
||||
QLIST_ENTRY (QEMUSoundCard) entries;
|
||||
} QEMUSoundCard;
|
||||
|
||||
@ -92,7 +95,8 @@ void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
|
||||
|
||||
void AUD_register_card (const char *name, QEMUSoundCard *card);
|
||||
void AUD_remove_card (QEMUSoundCard *card);
|
||||
CaptureVoiceOut *AUD_add_capture (
|
||||
CaptureVoiceOut *AUD_add_capture(
|
||||
AudioState *s,
|
||||
struct audsettings *as,
|
||||
struct audio_capture_ops *ops,
|
||||
void *opaque
|
||||
@ -109,7 +113,7 @@ SWVoiceOut *AUD_open_out (
|
||||
);
|
||||
|
||||
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
|
||||
int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size);
|
||||
size_t AUD_write (SWVoiceOut *sw, void *pcm_buf, size_t size);
|
||||
int AUD_get_buffer_size_out (SWVoiceOut *sw);
|
||||
void AUD_set_active_out (SWVoiceOut *sw, int on);
|
||||
int AUD_is_active_out (SWVoiceOut *sw);
|
||||
@ -130,7 +134,7 @@ SWVoiceIn *AUD_open_in (
|
||||
);
|
||||
|
||||
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
|
||||
int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
|
||||
size_t AUD_read (SWVoiceIn *sw, void *pcm_buf, size_t size);
|
||||
void AUD_set_active_in (SWVoiceIn *sw, int on);
|
||||
int AUD_is_active_in (SWVoiceIn *sw);
|
||||
|
||||
@ -143,25 +147,8 @@ static inline void *advance (void *p, int incr)
|
||||
return (d + incr);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define audio_MIN(a, b) ( __extension__ ({ \
|
||||
__typeof (a) ta = a; \
|
||||
__typeof (b) tb = b; \
|
||||
((ta)>(tb)?(tb):(ta)); \
|
||||
}))
|
||||
|
||||
#define audio_MAX(a, b) ( __extension__ ({ \
|
||||
__typeof (a) ta = a; \
|
||||
__typeof (b) tb = b; \
|
||||
((ta)<(tb)?(tb):(ta)); \
|
||||
}))
|
||||
#else
|
||||
#define audio_MIN(a, b) ((a)>(b)?(b):(a))
|
||||
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
|
||||
#endif
|
||||
|
||||
int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||
int bits, int nchannels);
|
||||
int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
|
||||
int freq, int bits, int nchannels);
|
||||
|
||||
bool audio_is_cleaning_up(void);
|
||||
void audio_cleanup(void);
|
||||
@ -175,4 +162,10 @@ void audio_parse_option(const char *opt);
|
||||
void audio_init_audiodevs(void);
|
||||
void audio_legacy_help(void);
|
||||
|
||||
AudioState *audio_state_by_name(const char *name);
|
||||
const char *audio_get_id(QEMUSoundCard *card);
|
||||
|
||||
#define DEFINE_AUDIO_PROPERTIES(_s, _f) \
|
||||
DEFINE_PROP_AUDIODEV("audiodev", _s, _f)
|
||||
|
||||
#endif /* QEMU_AUDIO_H */
|
||||
|
@ -49,9 +49,11 @@ struct audio_pcm_info {
|
||||
int swap_endianness;
|
||||
};
|
||||
|
||||
typedef struct AudioState AudioState;
|
||||
typedef struct SWVoiceCap SWVoiceCap;
|
||||
|
||||
typedef struct HWVoiceOut {
|
||||
AudioState *s;
|
||||
int enabled;
|
||||
int poll_mode;
|
||||
int pending_disable;
|
||||
@ -59,12 +61,12 @@ typedef struct HWVoiceOut {
|
||||
|
||||
f_sample *clip;
|
||||
|
||||
int rpos;
|
||||
size_t rpos;
|
||||
uint64_t ts_helper;
|
||||
|
||||
struct st_sample *mix_buf;
|
||||
|
||||
int samples;
|
||||
size_t samples;
|
||||
QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
|
||||
QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
|
||||
int ctl_caps;
|
||||
@ -73,19 +75,20 @@ typedef struct HWVoiceOut {
|
||||
} HWVoiceOut;
|
||||
|
||||
typedef struct HWVoiceIn {
|
||||
AudioState *s;
|
||||
int enabled;
|
||||
int poll_mode;
|
||||
struct audio_pcm_info info;
|
||||
|
||||
t_sample *conv;
|
||||
|
||||
int wpos;
|
||||
int total_samples_captured;
|
||||
size_t wpos;
|
||||
size_t total_samples_captured;
|
||||
uint64_t ts_helper;
|
||||
|
||||
struct st_sample *conv_buf;
|
||||
|
||||
int samples;
|
||||
size_t samples;
|
||||
QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
|
||||
int ctl_caps;
|
||||
struct audio_pcm_ops *pcm_ops;
|
||||
@ -94,12 +97,13 @@ typedef struct HWVoiceIn {
|
||||
|
||||
struct SWVoiceOut {
|
||||
QEMUSoundCard *card;
|
||||
AudioState *s;
|
||||
struct audio_pcm_info info;
|
||||
t_sample *conv;
|
||||
int64_t ratio;
|
||||
struct st_sample *buf;
|
||||
void *rate;
|
||||
int total_hw_samples_mixed;
|
||||
size_t total_hw_samples_mixed;
|
||||
int active;
|
||||
int empty;
|
||||
HWVoiceOut *hw;
|
||||
@ -111,11 +115,12 @@ struct SWVoiceOut {
|
||||
|
||||
struct SWVoiceIn {
|
||||
QEMUSoundCard *card;
|
||||
AudioState *s;
|
||||
int active;
|
||||
struct audio_pcm_info info;
|
||||
int64_t ratio;
|
||||
void *rate;
|
||||
int total_hw_samples_acquired;
|
||||
size_t total_hw_samples_acquired;
|
||||
struct st_sample *buf;
|
||||
f_sample *clip;
|
||||
HWVoiceIn *hw;
|
||||
@ -144,14 +149,12 @@ struct audio_driver {
|
||||
struct audio_pcm_ops {
|
||||
int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
|
||||
void (*fini_out)(HWVoiceOut *hw);
|
||||
int (*run_out) (HWVoiceOut *hw, int live);
|
||||
int (*write) (SWVoiceOut *sw, void *buf, int size);
|
||||
size_t (*run_out)(HWVoiceOut *hw, size_t live);
|
||||
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
|
||||
|
||||
int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
|
||||
void (*fini_in) (HWVoiceIn *hw);
|
||||
int (*run_in) (HWVoiceIn *hw);
|
||||
int (*read) (SWVoiceIn *sw, void *buf, int size);
|
||||
size_t (*run_in)(HWVoiceIn *hw);
|
||||
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
|
||||
};
|
||||
|
||||
@ -188,6 +191,11 @@ typedef struct AudioState {
|
||||
int nb_hw_voices_in;
|
||||
int vm_running;
|
||||
int64_t period_ticks;
|
||||
|
||||
bool timer_running;
|
||||
uint64_t timer_last;
|
||||
|
||||
QTAILQ_ENTRY(AudioState) list;
|
||||
} AudioState;
|
||||
|
||||
extern const struct mixeng_volume nominal_volume;
|
||||
@ -200,18 +208,15 @@ audio_driver *audio_driver_lookup(const char *name);
|
||||
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
|
||||
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
|
||||
|
||||
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
|
||||
int audio_pcm_hw_get_live_in (HWVoiceIn *hw);
|
||||
size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw);
|
||||
|
||||
int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
|
||||
|
||||
int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
|
||||
int live, int pending);
|
||||
size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
|
||||
size_t live, size_t pending);
|
||||
|
||||
int audio_bug (const char *funcname, int cond);
|
||||
void *audio_calloc (const char *funcname, int nmemb, size_t size);
|
||||
|
||||
void audio_run (const char *msg);
|
||||
void audio_run(AudioState *s, const char *msg);
|
||||
|
||||
#define VOICE_ENABLE 1
|
||||
#define VOICE_DISABLE 2
|
||||
@ -219,7 +224,7 @@ void audio_run (const char *msg);
|
||||
|
||||
#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
|
||||
|
||||
static inline int audio_ring_dist (int dst, int src, int len)
|
||||
static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
|
||||
{
|
||||
return (dst >= src) ? (dst - src) : (len - src + dst);
|
||||
}
|
||||
|
@ -36,9 +36,9 @@
|
||||
#define HWBUF hw->conv_buf
|
||||
#endif
|
||||
|
||||
static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
|
||||
static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
|
||||
struct audio_driver *drv)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
int max_voices = glue (drv->max_voices_, TYPE);
|
||||
int voice_size = glue (drv->voice_size_, TYPE);
|
||||
|
||||
@ -75,16 +75,16 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
|
||||
HWBUF = NULL;
|
||||
}
|
||||
|
||||
static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
|
||||
static bool glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
|
||||
{
|
||||
HWBUF = audio_calloc(__func__, hw->samples, sizeof(struct st_sample));
|
||||
if (!HWBUF) {
|
||||
dolog ("Could not allocate " NAME " buffer (%d samples)\n",
|
||||
hw->samples);
|
||||
return -1;
|
||||
dolog("Could not allocate " NAME " buffer (%zu samples)\n",
|
||||
hw->samples);
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
|
||||
@ -183,8 +183,8 @@ static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
|
||||
|
||||
static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
HW *hw = *hwp;
|
||||
AudioState *s = hw->s;
|
||||
|
||||
if (!hw->sw_head.lh_first) {
|
||||
#ifdef DAC
|
||||
@ -199,15 +199,14 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
|
||||
}
|
||||
}
|
||||
|
||||
static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
|
||||
static HW *glue(audio_pcm_hw_find_any_, TYPE)(AudioState *s, HW *hw)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
|
||||
}
|
||||
|
||||
static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
|
||||
static HW *glue(audio_pcm_hw_find_any_enabled_, TYPE)(AudioState *s, HW *hw)
|
||||
{
|
||||
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
|
||||
while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
|
||||
if (hw->enabled) {
|
||||
return hw;
|
||||
}
|
||||
@ -215,12 +214,10 @@ static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
||||
HW *hw,
|
||||
struct audsettings *as
|
||||
)
|
||||
static HW *glue(audio_pcm_hw_find_specific_, TYPE)(AudioState *s, HW *hw,
|
||||
struct audsettings *as)
|
||||
{
|
||||
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
|
||||
while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
|
||||
if (audio_pcm_info_eq (&hw->info, as)) {
|
||||
return hw;
|
||||
}
|
||||
@ -228,10 +225,10 @@ static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
|
||||
static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
|
||||
struct audsettings *as)
|
||||
{
|
||||
HW *hw;
|
||||
AudioState *s = &glob_audio_state;
|
||||
struct audio_driver *drv = s->drv;
|
||||
|
||||
if (!glue (s->nb_hw_voices_, TYPE)) {
|
||||
@ -255,6 +252,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hw->s = s;
|
||||
hw->pcm_ops = drv->pcm_ops;
|
||||
hw->ctl_caps = drv->ctl_caps;
|
||||
|
||||
@ -267,7 +265,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, hw->samples <= 0)) {
|
||||
dolog ("hw->samples=%d\n", hw->samples);
|
||||
dolog("hw->samples=%zd\n", hw->samples);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
@ -281,7 +279,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index (hw->info.bits)];
|
||||
|
||||
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
|
||||
if (!glue(audio_pcm_hw_alloc_resources_, TYPE)(hw)) {
|
||||
goto err1;
|
||||
}
|
||||
|
||||
@ -328,33 +326,33 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
||||
abort();
|
||||
}
|
||||
|
||||
static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
|
||||
static HW *glue(audio_pcm_hw_add_, TYPE)(AudioState *s, struct audsettings *as)
|
||||
{
|
||||
HW *hw;
|
||||
AudioState *s = &glob_audio_state;
|
||||
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
||||
|
||||
if (pdo->fixed_settings) {
|
||||
hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
|
||||
hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
|
||||
if (hw) {
|
||||
return hw;
|
||||
}
|
||||
}
|
||||
|
||||
hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
|
||||
hw = glue(audio_pcm_hw_find_specific_, TYPE)(s, NULL, as);
|
||||
if (hw) {
|
||||
return hw;
|
||||
}
|
||||
|
||||
hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
|
||||
hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
|
||||
if (hw) {
|
||||
return hw;
|
||||
}
|
||||
|
||||
return glue (audio_pcm_hw_find_any_, TYPE) (NULL);
|
||||
return glue(audio_pcm_hw_find_any_, TYPE)(s, NULL);
|
||||
}
|
||||
|
||||
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
|
||||
AudioState *s,
|
||||
const char *sw_name,
|
||||
struct audsettings *as
|
||||
)
|
||||
@ -362,7 +360,6 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
SW *sw;
|
||||
HW *hw;
|
||||
struct audsettings hw_as;
|
||||
AudioState *s = &glob_audio_state;
|
||||
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
||||
|
||||
if (pdo->fixed_settings) {
|
||||
@ -378,8 +375,9 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
sw_name ? sw_name : "unknown", sizeof (*sw));
|
||||
goto err1;
|
||||
}
|
||||
sw->s = s;
|
||||
|
||||
hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as);
|
||||
hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
|
||||
if (!hw) {
|
||||
goto err2;
|
||||
}
|
||||
@ -430,7 +428,7 @@ SW *glue (AUD_open_, TYPE) (
|
||||
struct audsettings *as
|
||||
)
|
||||
{
|
||||
AudioState *s = &glob_audio_state;
|
||||
AudioState *s = card->state;
|
||||
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
||||
|
||||
if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
|
||||
@ -476,7 +474,7 @@ SW *glue (AUD_open_, TYPE) (
|
||||
}
|
||||
}
|
||||
else {
|
||||
sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as);
|
||||
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
|
||||
if (!sw) {
|
||||
dolog ("Failed to create voice `%s'\n", name);
|
||||
return NULL;
|
||||
|
@ -43,9 +43,9 @@ typedef struct coreaudioVoiceOut {
|
||||
UInt32 audioDevicePropertyBufferFrameSize;
|
||||
AudioStreamBasicDescription outputStreamBasicDescription;
|
||||
AudioDeviceIOProcID ioprocid;
|
||||
int live;
|
||||
int decr;
|
||||
int rpos;
|
||||
size_t live;
|
||||
size_t decr;
|
||||
size_t rpos;
|
||||
} coreaudioVoiceOut;
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
@ -397,9 +397,9 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coreaudio_run_out (HWVoiceOut *hw, int live)
|
||||
static size_t coreaudio_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
int decr;
|
||||
size_t decr;
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
|
||||
if (coreaudio_lock (core, "coreaudio_run_out")) {
|
||||
@ -413,7 +413,7 @@ static int coreaudio_run_out (HWVoiceOut *hw, int live)
|
||||
core->live);
|
||||
}
|
||||
|
||||
decr = audio_MIN (core->decr, live);
|
||||
decr = MIN (core->decr, live);
|
||||
core->decr -= decr;
|
||||
|
||||
core->live = live - decr;
|
||||
@ -489,11 +489,6 @@ static OSStatus audioDeviceIOProc(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
{
|
||||
@ -692,7 +687,6 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
|
||||
.init_out = coreaudio_init_out,
|
||||
.fini_out = coreaudio_fini_out,
|
||||
.run_out = coreaudio_run_out,
|
||||
.write = coreaudio_write,
|
||||
.ctl_out = coreaudio_ctl_out
|
||||
};
|
||||
|
||||
|
@ -454,24 +454,20 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsound_write (SWVoiceOut *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
static int dsound_run_out (HWVoiceOut *hw, int live)
|
||||
static size_t dsound_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
int err;
|
||||
HRESULT hr;
|
||||
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
||||
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
||||
int len, hwshift;
|
||||
size_t len;
|
||||
int hwshift;
|
||||
DWORD blen1, blen2;
|
||||
DWORD len1, len2;
|
||||
DWORD decr;
|
||||
DWORD wpos, ppos, old_pos;
|
||||
LPVOID p1, p2;
|
||||
int bufsize;
|
||||
size_t bufsize;
|
||||
dsound *s = ds->s;
|
||||
AudiodevDsoundOptions *dso = &s->dev->u.dsound;
|
||||
|
||||
@ -538,9 +534,9 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_bug(__func__, len < 0 || len > bufsize)) {
|
||||
dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
|
||||
len, bufsize, old_pos, ppos);
|
||||
if (audio_bug(__func__, len > bufsize)) {
|
||||
dolog("len=%zu bufsize=%zu old_pos=%ld ppos=%ld\n",
|
||||
len, bufsize, old_pos, ppos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -645,18 +641,13 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsound_read (SWVoiceIn *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_read (sw, buf, len);
|
||||
}
|
||||
|
||||
static int dsound_run_in (HWVoiceIn *hw)
|
||||
static size_t dsound_run_in(HWVoiceIn *hw)
|
||||
{
|
||||
int err;
|
||||
HRESULT hr;
|
||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||
int live, len, dead;
|
||||
size_t live, len, dead;
|
||||
DWORD blen1, blen2;
|
||||
DWORD len1, len2;
|
||||
DWORD decr;
|
||||
@ -707,7 +698,7 @@ static int dsound_run_in (HWVoiceIn *hw)
|
||||
if (!len) {
|
||||
return 0;
|
||||
}
|
||||
len = audio_MIN (len, dead);
|
||||
len = MIN (len, dead);
|
||||
|
||||
err = dsound_lock_in (
|
||||
dscb,
|
||||
@ -856,13 +847,11 @@ static struct audio_pcm_ops dsound_pcm_ops = {
|
||||
.init_out = dsound_init_out,
|
||||
.fini_out = dsound_fini_out,
|
||||
.run_out = dsound_run_out,
|
||||
.write = dsound_write,
|
||||
.ctl_out = dsound_ctl_out,
|
||||
|
||||
.init_in = dsound_init_in,
|
||||
.fini_in = dsound_fini_in,
|
||||
.run_in = dsound_run_in,
|
||||
.read = dsound_read,
|
||||
.ctl_in = dsound_ctl_in
|
||||
};
|
||||
|
||||
|
@ -33,6 +33,7 @@ struct st_sample { mixeng_real l; mixeng_real r; };
|
||||
struct mixeng_volume { int mute; int64_t r; int64_t l; };
|
||||
struct st_sample { int64_t l; int64_t r; };
|
||||
#endif
|
||||
typedef struct st_sample st_sample;
|
||||
|
||||
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
|
||||
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
|
||||
@ -41,10 +42,10 @@ extern t_sample *mixeng_conv[2][2][2][3];
|
||||
extern f_sample *mixeng_clip[2][2][2][3];
|
||||
|
||||
void *st_rate_start (int inrate, int outrate);
|
||||
void st_rate_flow (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
||||
int *isamp, int *osamp);
|
||||
void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
||||
int *isamp, int *osamp);
|
||||
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||
size_t *isamp, size_t *osamp);
|
||||
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||
size_t *isamp, size_t *osamp);
|
||||
void st_rate_stop (void *opaque);
|
||||
void mixeng_clear (struct st_sample *buf, int len);
|
||||
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
||||
|
@ -41,10 +41,10 @@ typedef struct NoVoiceIn {
|
||||
int64_t old_ticks;
|
||||
} NoVoiceIn;
|
||||
|
||||
static int no_run_out (HWVoiceOut *hw, int live)
|
||||
static size_t no_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
NoVoiceOut *no = (NoVoiceOut *) hw;
|
||||
int decr, samples;
|
||||
size_t decr, samples;
|
||||
int64_t now;
|
||||
int64_t ticks;
|
||||
int64_t bytes;
|
||||
@ -52,20 +52,15 @@ static int no_run_out (HWVoiceOut *hw, int live)
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
ticks = now - no->old_ticks;
|
||||
bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
|
||||
bytes = audio_MIN(bytes, INT_MAX);
|
||||
bytes = MIN(bytes, SIZE_MAX);
|
||||
samples = bytes >> hw->info.shift;
|
||||
|
||||
no->old_ticks = now;
|
||||
decr = audio_MIN (live, samples);
|
||||
decr = MIN (live, samples);
|
||||
hw->rpos = (hw->rpos + decr) % hw->samples;
|
||||
return decr;
|
||||
}
|
||||
|
||||
static int no_write (SWVoiceOut *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_write(sw, buf, len);
|
||||
}
|
||||
|
||||
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
||||
{
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
@ -97,12 +92,12 @@ static void no_fini_in (HWVoiceIn *hw)
|
||||
(void) hw;
|
||||
}
|
||||
|
||||
static int no_run_in (HWVoiceIn *hw)
|
||||
static size_t no_run_in(HWVoiceIn *hw)
|
||||
{
|
||||
NoVoiceIn *no = (NoVoiceIn *) hw;
|
||||
int live = audio_pcm_hw_get_live_in (hw);
|
||||
int dead = hw->samples - live;
|
||||
int samples = 0;
|
||||
size_t live = audio_pcm_hw_get_live_in(hw);
|
||||
size_t dead = hw->samples - live;
|
||||
size_t samples = 0;
|
||||
|
||||
if (dead) {
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
@ -111,25 +106,13 @@ static int no_run_in (HWVoiceIn *hw)
|
||||
muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
|
||||
|
||||
no->old_ticks = now;
|
||||
bytes = audio_MIN (bytes, INT_MAX);
|
||||
bytes = MIN (bytes, SIZE_MAX);
|
||||
samples = bytes >> hw->info.shift;
|
||||
samples = audio_MIN (samples, dead);
|
||||
samples = MIN (samples, dead);
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
static int no_read (SWVoiceIn *sw, void *buf, int size)
|
||||
{
|
||||
/* use custom code here instead of audio_pcm_sw_read() to avoid
|
||||
* useless resampling/mixing */
|
||||
int samples = size >> sw->info.shift;
|
||||
int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
int to_clear = audio_MIN (samples, total);
|
||||
sw->total_hw_samples_acquired += total;
|
||||
audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
|
||||
return to_clear << sw->info.shift;
|
||||
}
|
||||
|
||||
static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||
{
|
||||
(void) hw;
|
||||
@ -151,13 +134,11 @@ static struct audio_pcm_ops no_pcm_ops = {
|
||||
.init_out = no_init_out,
|
||||
.fini_out = no_fini_out,
|
||||
.run_out = no_run_out,
|
||||
.write = no_write,
|
||||
.ctl_out = no_ctl_out,
|
||||
|
||||
.init_in = no_init_in,
|
||||
.fini_in = no_fini_in,
|
||||
.run_in = no_run_in,
|
||||
.read = no_read,
|
||||
.ctl_in = no_ctl_in
|
||||
};
|
||||
|
||||
|
@ -110,33 +110,28 @@ static void oss_anal_close (int *fdp)
|
||||
|
||||
static void oss_helper_poll_out (void *opaque)
|
||||
{
|
||||
(void) opaque;
|
||||
audio_run ("oss_poll_out");
|
||||
AudioState *s = opaque;
|
||||
audio_run(s, "oss_poll_out");
|
||||
}
|
||||
|
||||
static void oss_helper_poll_in (void *opaque)
|
||||
{
|
||||
(void) opaque;
|
||||
audio_run ("oss_poll_in");
|
||||
AudioState *s = opaque;
|
||||
audio_run(s, "oss_poll_in");
|
||||
}
|
||||
|
||||
static void oss_poll_out (HWVoiceOut *hw)
|
||||
{
|
||||
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||
|
||||
qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
|
||||
qemu_set_fd_handler(oss->fd, NULL, oss_helper_poll_out, hw->s);
|
||||
}
|
||||
|
||||
static void oss_poll_in (HWVoiceIn *hw)
|
||||
{
|
||||
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
||||
|
||||
qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
|
||||
}
|
||||
|
||||
static int oss_write (SWVoiceOut *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s);
|
||||
}
|
||||
|
||||
static int aud_to_ossfmt (AudioFormat fmt, int endianness)
|
||||
@ -388,7 +383,7 @@ static void oss_write_pending (OSSVoiceOut *oss)
|
||||
int samples_written;
|
||||
ssize_t bytes_written;
|
||||
int samples_till_end = hw->samples - oss->wpos;
|
||||
int samples_to_write = audio_MIN (oss->pending, samples_till_end);
|
||||
int samples_to_write = MIN (oss->pending, samples_till_end);
|
||||
int bytes_to_write = samples_to_write << hw->info.shift;
|
||||
void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
|
||||
|
||||
@ -416,13 +411,14 @@ static void oss_write_pending (OSSVoiceOut *oss)
|
||||
}
|
||||
}
|
||||
|
||||
static int oss_run_out (HWVoiceOut *hw, int live)
|
||||
static size_t oss_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||
int err, decr;
|
||||
int err;
|
||||
size_t decr;
|
||||
struct audio_buf_info abinfo;
|
||||
struct count_info cntinfo;
|
||||
int bufsize;
|
||||
size_t bufsize;
|
||||
|
||||
bufsize = hw->samples << hw->info.shift;
|
||||
|
||||
@ -437,7 +433,7 @@ static int oss_run_out (HWVoiceOut *hw, int live)
|
||||
|
||||
pos = hw->rpos << hw->info.shift;
|
||||
bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
|
||||
decr = audio_MIN (bytes >> hw->info.shift, live);
|
||||
decr = MIN (bytes >> hw->info.shift, live);
|
||||
}
|
||||
else {
|
||||
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
|
||||
@ -456,7 +452,7 @@ static int oss_run_out (HWVoiceOut *hw, int live)
|
||||
return 0;
|
||||
}
|
||||
|
||||
decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
|
||||
decr = MIN (abinfo.bytes >> hw->info.shift, live);
|
||||
if (!decr) {
|
||||
return 0;
|
||||
}
|
||||
@ -481,8 +477,8 @@ static void oss_fini_out (HWVoiceOut *hw)
|
||||
if (oss->mmapped) {
|
||||
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
|
||||
if (err) {
|
||||
oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
|
||||
oss->pcm_buf, hw->samples << hw->info.shift);
|
||||
oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n",
|
||||
oss->pcm_buf, hw->samples << hw->info.shift);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -548,8 +544,8 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
0
|
||||
);
|
||||
if (oss->pcm_buf == MAP_FAILED) {
|
||||
oss_logerr (errno, "Failed to map %d bytes of DAC\n",
|
||||
hw->samples << hw->info.shift);
|
||||
oss_logerr(errno, "Failed to map %zu bytes of DAC\n",
|
||||
hw->samples << hw->info.shift);
|
||||
}
|
||||
else {
|
||||
int err;
|
||||
@ -573,8 +569,8 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
if (!oss->mmapped) {
|
||||
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
|
||||
if (err) {
|
||||
oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
|
||||
oss->pcm_buf, hw->samples << hw->info.shift);
|
||||
oss_logerr(errno, "Failed to unmap buffer %p size %zu\n",
|
||||
oss->pcm_buf, hw->samples << hw->info.shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -586,7 +582,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
1 << hw->info.shift);
|
||||
if (!oss->pcm_buf) {
|
||||
dolog (
|
||||
"Could not allocate DAC buffer (%d samples, each %d bytes)\n",
|
||||
"Could not allocate DAC buffer (%zu samples, each %d bytes)\n",
|
||||
hw->samples,
|
||||
1 << hw->info.shift
|
||||
);
|
||||
@ -698,8 +694,8 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
|
||||
oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
if (!oss->pcm_buf) {
|
||||
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
dolog("Could not allocate ADC buffer (%zu samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
oss_anal_close (&fd);
|
||||
return -1;
|
||||
}
|
||||
@ -719,17 +715,17 @@ static void oss_fini_in (HWVoiceIn *hw)
|
||||
oss->pcm_buf = NULL;
|
||||
}
|
||||
|
||||
static int oss_run_in (HWVoiceIn *hw)
|
||||
static size_t oss_run_in(HWVoiceIn *hw)
|
||||
{
|
||||
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
||||
int hwshift = hw->info.shift;
|
||||
int i;
|
||||
int live = audio_pcm_hw_get_live_in (hw);
|
||||
int dead = hw->samples - live;
|
||||
size_t live = audio_pcm_hw_get_live_in (hw);
|
||||
size_t dead = hw->samples - live;
|
||||
size_t read_samples = 0;
|
||||
struct {
|
||||
int add;
|
||||
int len;
|
||||
size_t add;
|
||||
size_t len;
|
||||
} bufs[2] = {
|
||||
{ .add = hw->wpos, .len = 0 },
|
||||
{ .add = 0, .len = 0 }
|
||||
@ -756,9 +752,9 @@ static int oss_run_in (HWVoiceIn *hw)
|
||||
|
||||
if (nread > 0) {
|
||||
if (nread & hw->info.align) {
|
||||
dolog ("warning: Misaligned read %zd (requested %d), "
|
||||
"alignment %d\n", nread, bufs[i].add << hwshift,
|
||||
hw->info.align + 1);
|
||||
dolog("warning: Misaligned read %zd (requested %zu), "
|
||||
"alignment %d\n", nread, bufs[i].add << hwshift,
|
||||
hw->info.align + 1);
|
||||
}
|
||||
read_samples += nread >> hwshift;
|
||||
hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
|
||||
@ -771,9 +767,9 @@ static int oss_run_in (HWVoiceIn *hw)
|
||||
case EAGAIN:
|
||||
break;
|
||||
default:
|
||||
oss_logerr (
|
||||
oss_logerr(
|
||||
errno,
|
||||
"Failed to read %d bytes of audio (to %p)\n",
|
||||
"Failed to read %zu bytes of audio (to %p)\n",
|
||||
bufs[i].len, p
|
||||
);
|
||||
break;
|
||||
@ -788,11 +784,6 @@ static int oss_run_in (HWVoiceIn *hw)
|
||||
return read_samples;
|
||||
}
|
||||
|
||||
static int oss_read (SWVoiceIn *sw, void *buf, int size)
|
||||
{
|
||||
return audio_pcm_sw_read (sw, buf, size);
|
||||
}
|
||||
|
||||
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||
{
|
||||
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
||||
@ -855,13 +846,11 @@ static struct audio_pcm_ops oss_pcm_ops = {
|
||||
.init_out = oss_init_out,
|
||||
.fini_out = oss_fini_out,
|
||||
.run_out = oss_run_out,
|
||||
.write = oss_write,
|
||||
.ctl_out = oss_ctl_out,
|
||||
|
||||
.init_in = oss_init_in,
|
||||
.fini_in = oss_fini_in,
|
||||
.run_in = oss_run_in,
|
||||
.read = oss_read,
|
||||
.ctl_in = oss_ctl_in
|
||||
};
|
||||
|
||||
|
421
audio/paaudio.c
421
audio/paaudio.c
@ -11,41 +11,52 @@
|
||||
#include "audio_int.h"
|
||||
#include "audio_pt_int.h"
|
||||
|
||||
typedef struct {
|
||||
Audiodev *dev;
|
||||
typedef struct PAConnection {
|
||||
char *server;
|
||||
int refcount;
|
||||
QTAILQ_ENTRY(PAConnection) list;
|
||||
|
||||
pa_threaded_mainloop *mainloop;
|
||||
pa_context *context;
|
||||
} PAConnection;
|
||||
|
||||
static QTAILQ_HEAD(PAConnectionHead, PAConnection) pa_conns =
|
||||
QTAILQ_HEAD_INITIALIZER(pa_conns);
|
||||
|
||||
typedef struct {
|
||||
Audiodev *dev;
|
||||
PAConnection *conn;
|
||||
} paaudio;
|
||||
|
||||
typedef struct {
|
||||
HWVoiceOut hw;
|
||||
int done;
|
||||
int live;
|
||||
int decr;
|
||||
int rpos;
|
||||
size_t done;
|
||||
size_t live;
|
||||
size_t decr;
|
||||
size_t rpos;
|
||||
pa_stream *stream;
|
||||
void *pcm_buf;
|
||||
struct audio_pt pt;
|
||||
paaudio *g;
|
||||
int samples;
|
||||
size_t samples;
|
||||
} PAVoiceOut;
|
||||
|
||||
typedef struct {
|
||||
HWVoiceIn hw;
|
||||
int done;
|
||||
int dead;
|
||||
int incr;
|
||||
int wpos;
|
||||
size_t done;
|
||||
size_t dead;
|
||||
size_t incr;
|
||||
size_t wpos;
|
||||
pa_stream *stream;
|
||||
void *pcm_buf;
|
||||
struct audio_pt pt;
|
||||
const void *read_data;
|
||||
size_t read_index, read_length;
|
||||
paaudio *g;
|
||||
int samples;
|
||||
size_t samples;
|
||||
} PAVoiceIn;
|
||||
|
||||
static void qpa_audio_fini(void *opaque);
|
||||
static void qpa_conn_fini(PAConnection *c);
|
||||
|
||||
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
|
||||
{
|
||||
@ -108,11 +119,11 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
|
||||
|
||||
static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
|
||||
{
|
||||
paaudio *g = p->g;
|
||||
PAConnection *c = p->g->conn;
|
||||
|
||||
pa_threaded_mainloop_lock (g->mainloop);
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
|
||||
CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
|
||||
|
||||
while (length > 0) {
|
||||
size_t l;
|
||||
@ -121,11 +132,11 @@ static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror
|
||||
int r;
|
||||
|
||||
r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
|
||||
CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
|
||||
CHECK_SUCCESS_GOTO(c, rerror, r == 0, unlock_and_fail);
|
||||
|
||||
if (!p->read_data) {
|
||||
pa_threaded_mainloop_wait (g->mainloop);
|
||||
CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
|
||||
pa_threaded_mainloop_wait(c->mainloop);
|
||||
CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
|
||||
} else {
|
||||
p->read_index = 0;
|
||||
}
|
||||
@ -148,53 +159,53 @@ static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror
|
||||
p->read_length = 0;
|
||||
p->read_index = 0;
|
||||
|
||||
CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
|
||||
CHECK_SUCCESS_GOTO(c, rerror, r == 0, unlock_and_fail);
|
||||
}
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return 0;
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
|
||||
{
|
||||
paaudio *g = p->g;
|
||||
PAConnection *c = p->g->conn;
|
||||
|
||||
pa_threaded_mainloop_lock (g->mainloop);
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
|
||||
CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
|
||||
|
||||
while (length > 0) {
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
while (!(l = pa_stream_writable_size (p->stream))) {
|
||||
pa_threaded_mainloop_wait (g->mainloop);
|
||||
CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
|
||||
pa_threaded_mainloop_wait(c->mainloop);
|
||||
CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
|
||||
}
|
||||
|
||||
CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
|
||||
CHECK_SUCCESS_GOTO(c, rerror, l != (size_t) -1, unlock_and_fail);
|
||||
|
||||
if (l > length) {
|
||||
l = length;
|
||||
}
|
||||
|
||||
r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
|
||||
CHECK_SUCCESS_GOTO(c, rerror, r >= 0, unlock_and_fail);
|
||||
|
||||
data = (const uint8_t *) data + l;
|
||||
length -= l;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return 0;
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -208,7 +219,7 @@ static void *qpa_thread_out (void *arg)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int decr, to_mix, rpos;
|
||||
size_t decr, to_mix, rpos;
|
||||
|
||||
for (;;) {
|
||||
if (pa->done) {
|
||||
@ -224,7 +235,7 @@ static void *qpa_thread_out (void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
decr = to_mix = audio_MIN(pa->live, pa->samples >> 5);
|
||||
decr = to_mix = MIN(pa->live, pa->samples >> 5);
|
||||
rpos = pa->rpos;
|
||||
|
||||
if (audio_pt_unlock(&pa->pt, __func__)) {
|
||||
@ -233,7 +244,7 @@ static void *qpa_thread_out (void *arg)
|
||||
|
||||
while (to_mix) {
|
||||
int error;
|
||||
int chunk = audio_MIN (to_mix, hw->samples - rpos);
|
||||
size_t chunk = MIN (to_mix, hw->samples - rpos);
|
||||
struct st_sample *src = hw->mix_buf + rpos;
|
||||
|
||||
hw->clip (pa->pcm_buf, src, chunk);
|
||||
@ -262,16 +273,16 @@ static void *qpa_thread_out (void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int qpa_run_out (HWVoiceOut *hw, int live)
|
||||
static size_t qpa_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
int decr;
|
||||
size_t decr;
|
||||
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
decr = audio_MIN (live, pa->decr);
|
||||
decr = MIN (live, pa->decr);
|
||||
pa->decr -= decr;
|
||||
pa->live = live - decr;
|
||||
hw->rpos = pa->rpos;
|
||||
@ -284,11 +295,6 @@ static int qpa_run_out (HWVoiceOut *hw, int live)
|
||||
return decr;
|
||||
}
|
||||
|
||||
static int qpa_write (SWVoiceOut *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
/* capture */
|
||||
static void *qpa_thread_in (void *arg)
|
||||
{
|
||||
@ -300,7 +306,7 @@ static void *qpa_thread_in (void *arg)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int incr, to_grab, wpos;
|
||||
size_t incr, to_grab, wpos;
|
||||
|
||||
for (;;) {
|
||||
if (pa->done) {
|
||||
@ -316,7 +322,7 @@ static void *qpa_thread_in (void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
incr = to_grab = audio_MIN(pa->dead, pa->samples >> 5);
|
||||
incr = to_grab = MIN(pa->dead, pa->samples >> 5);
|
||||
wpos = pa->wpos;
|
||||
|
||||
if (audio_pt_unlock(&pa->pt, __func__)) {
|
||||
@ -325,7 +331,7 @@ static void *qpa_thread_in (void *arg)
|
||||
|
||||
while (to_grab) {
|
||||
int error;
|
||||
int chunk = audio_MIN (to_grab, hw->samples - wpos);
|
||||
size_t chunk = MIN (to_grab, hw->samples - wpos);
|
||||
void *buf = advance (pa->pcm_buf, wpos);
|
||||
|
||||
if (qpa_simple_read (pa, buf,
|
||||
@ -353,9 +359,9 @@ static void *qpa_thread_in (void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int qpa_run_in (HWVoiceIn *hw)
|
||||
static size_t qpa_run_in(HWVoiceIn *hw)
|
||||
{
|
||||
int live, incr, dead;
|
||||
size_t live, incr, dead;
|
||||
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||
|
||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||
@ -364,7 +370,7 @@ static int qpa_run_in (HWVoiceIn *hw)
|
||||
|
||||
live = audio_pcm_hw_get_live_in (hw);
|
||||
dead = hw->samples - live;
|
||||
incr = audio_MIN (dead, pa->incr);
|
||||
incr = MIN (dead, pa->incr);
|
||||
pa->incr -= incr;
|
||||
pa->dead = dead - incr;
|
||||
hw->wpos = pa->wpos;
|
||||
@ -377,11 +383,6 @@ static int qpa_run_in (HWVoiceIn *hw)
|
||||
return incr;
|
||||
}
|
||||
|
||||
static int qpa_read (SWVoiceIn *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_read (sw, buf, len);
|
||||
}
|
||||
|
||||
static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
|
||||
{
|
||||
int format;
|
||||
@ -432,13 +433,13 @@ static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
|
||||
|
||||
static void context_state_cb (pa_context *c, void *userdata)
|
||||
{
|
||||
paaudio *g = userdata;
|
||||
PAConnection *conn = userdata;
|
||||
|
||||
switch (pa_context_get_state(c)) {
|
||||
case PA_CONTEXT_READY:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
case PA_CONTEXT_FAILED:
|
||||
pa_threaded_mainloop_signal (g->mainloop, 0);
|
||||
pa_threaded_mainloop_signal(conn->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
@ -451,14 +452,14 @@ static void context_state_cb (pa_context *c, void *userdata)
|
||||
|
||||
static void stream_state_cb (pa_stream *s, void * userdata)
|
||||
{
|
||||
paaudio *g = userdata;
|
||||
PAConnection *c = userdata;
|
||||
|
||||
switch (pa_stream_get_state (s)) {
|
||||
|
||||
case PA_STREAM_READY:
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
pa_threaded_mainloop_signal (g->mainloop, 0);
|
||||
pa_threaded_mainloop_signal(c->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
@ -469,13 +470,13 @@ static void stream_state_cb (pa_stream *s, void * userdata)
|
||||
|
||||
static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
|
||||
{
|
||||
paaudio *g = userdata;
|
||||
PAConnection *c = userdata;
|
||||
|
||||
pa_threaded_mainloop_signal (g->mainloop, 0);
|
||||
pa_threaded_mainloop_signal(c->mainloop, 0);
|
||||
}
|
||||
|
||||
static pa_stream *qpa_simple_new (
|
||||
paaudio *g,
|
||||
PAConnection *c,
|
||||
const char *name,
|
||||
pa_stream_direction_t dir,
|
||||
const char *dev,
|
||||
@ -486,50 +487,51 @@ static pa_stream *qpa_simple_new (
|
||||
{
|
||||
int r;
|
||||
pa_stream *stream;
|
||||
pa_stream_flags_t flags;
|
||||
|
||||
pa_threaded_mainloop_lock (g->mainloop);
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
stream = pa_stream_new (g->context, name, ss, map);
|
||||
stream = pa_stream_new(c->context, name, ss, map);
|
||||
if (!stream) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_stream_set_state_callback (stream, stream_state_cb, g);
|
||||
pa_stream_set_read_callback (stream, stream_request_cb, g);
|
||||
pa_stream_set_write_callback (stream, stream_request_cb, g);
|
||||
pa_stream_set_state_callback(stream, stream_state_cb, c);
|
||||
pa_stream_set_read_callback(stream, stream_request_cb, c);
|
||||
pa_stream_set_write_callback(stream, stream_request_cb, c);
|
||||
|
||||
flags =
|
||||
PA_STREAM_INTERPOLATE_TIMING
|
||||
| PA_STREAM_AUTO_TIMING_UPDATE
|
||||
| PA_STREAM_EARLY_REQUESTS;
|
||||
|
||||
if (dev) {
|
||||
/* don't move the stream if the user specified a sink/source */
|
||||
flags |= PA_STREAM_DONT_MOVE;
|
||||
}
|
||||
|
||||
if (dir == PA_STREAM_PLAYBACK) {
|
||||
r = pa_stream_connect_playback (stream, dev, attr,
|
||||
PA_STREAM_INTERPOLATE_TIMING
|
||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
||||
|PA_STREAM_ADJUST_LATENCY
|
||||
#endif
|
||||
|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
|
||||
r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL);
|
||||
} else {
|
||||
r = pa_stream_connect_record (stream, dev, attr,
|
||||
PA_STREAM_INTERPOLATE_TIMING
|
||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
||||
|PA_STREAM_ADJUST_LATENCY
|
||||
#endif
|
||||
|PA_STREAM_AUTO_TIMING_UPDATE);
|
||||
r = pa_stream_connect_record(stream, dev, attr, flags);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
|
||||
return stream;
|
||||
|
||||
fail:
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
|
||||
if (stream) {
|
||||
pa_stream_unref (stream);
|
||||
}
|
||||
|
||||
*rerror = pa_context_errno (g->context);
|
||||
*rerror = pa_context_errno(c->context);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -545,6 +547,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
paaudio *g = pa->g = drv_opaque;
|
||||
AudiodevPaOptions *popts = &g->dev->u.pa;
|
||||
AudiodevPaPerDirectionOptions *ppdo = popts->out;
|
||||
PAConnection *c = g->conn;
|
||||
|
||||
ss.format = audfmt_to_pa (as->fmt, as->endianness);
|
||||
ss.channels = as->nchannels;
|
||||
@ -558,7 +561,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
|
||||
|
||||
pa->stream = qpa_simple_new (
|
||||
g,
|
||||
c,
|
||||
"qemu",
|
||||
PA_STREAM_PLAYBACK,
|
||||
ppdo->has_name ? ppdo->name : NULL,
|
||||
@ -579,8 +582,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
pa->rpos = hw->rpos;
|
||||
if (!pa->pcm_buf) {
|
||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
||||
hw->samples << hw->info.shift);
|
||||
dolog("Could not allocate buffer (%zu bytes)\n",
|
||||
hw->samples << hw->info.shift);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
@ -612,6 +615,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
paaudio *g = pa->g = drv_opaque;
|
||||
AudiodevPaOptions *popts = &g->dev->u.pa;
|
||||
AudiodevPaPerDirectionOptions *ppdo = popts->in;
|
||||
PAConnection *c = g->conn;
|
||||
|
||||
ss.format = audfmt_to_pa (as->fmt, as->endianness);
|
||||
ss.channels = as->nchannels;
|
||||
@ -625,7 +629,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
|
||||
|
||||
pa->stream = qpa_simple_new (
|
||||
g,
|
||||
c,
|
||||
"qemu",
|
||||
PA_STREAM_RECORD,
|
||||
ppdo->has_name ? ppdo->name : NULL,
|
||||
@ -646,8 +650,8 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
pa->wpos = hw->wpos;
|
||||
if (!pa->pcm_buf) {
|
||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
||||
hw->samples << hw->info.shift);
|
||||
dolog("Could not allocate buffer (%zu bytes)\n",
|
||||
hw->samples << hw->info.shift);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
@ -669,6 +673,27 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
|
||||
{
|
||||
int err;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
/*
|
||||
* wait until actually connects. workaround pa bug #247
|
||||
* https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
|
||||
*/
|
||||
while (pa_stream_get_state(stream) == PA_STREAM_CREATING) {
|
||||
pa_threaded_mainloop_wait(c->mainloop);
|
||||
}
|
||||
|
||||
err = pa_stream_disconnect(stream);
|
||||
if (err != 0) {
|
||||
dolog("Failed to disconnect! err=%d\n", err);
|
||||
}
|
||||
pa_stream_unref(stream);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
|
||||
static void qpa_fini_out (HWVoiceOut *hw)
|
||||
{
|
||||
void *ret;
|
||||
@ -680,7 +705,7 @@ static void qpa_fini_out (HWVoiceOut *hw)
|
||||
audio_pt_join(&pa->pt, &ret, __func__);
|
||||
|
||||
if (pa->stream) {
|
||||
pa_stream_unref (pa->stream);
|
||||
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||
pa->stream = NULL;
|
||||
}
|
||||
|
||||
@ -700,7 +725,7 @@ static void qpa_fini_in (HWVoiceIn *hw)
|
||||
audio_pt_join(&pa->pt, &ret, __func__);
|
||||
|
||||
if (pa->stream) {
|
||||
pa_stream_unref (pa->stream);
|
||||
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||
pa->stream = NULL;
|
||||
}
|
||||
|
||||
@ -714,7 +739,7 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
||||
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||
pa_operation *op;
|
||||
pa_cvolume v;
|
||||
paaudio *g = pa->g;
|
||||
PAConnection *c = pa->g->conn;
|
||||
|
||||
#ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */
|
||||
pa_cvolume_init (&v); /* function is present in 0.9.13+ */
|
||||
@ -734,28 +759,29 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
||||
v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
|
||||
v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
|
||||
|
||||
pa_threaded_mainloop_lock (g->mainloop);
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
op = pa_context_set_sink_input_volume (g->context,
|
||||
op = pa_context_set_sink_input_volume(c->context,
|
||||
pa_stream_get_index (pa->stream),
|
||||
&v, NULL, NULL);
|
||||
if (!op)
|
||||
qpa_logerr (pa_context_errno (g->context),
|
||||
"set_sink_input_volume() failed\n");
|
||||
else
|
||||
pa_operation_unref (op);
|
||||
if (!op) {
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"set_sink_input_volume() failed\n");
|
||||
} else {
|
||||
pa_operation_unref(op);
|
||||
}
|
||||
|
||||
op = pa_context_set_sink_input_mute (g->context,
|
||||
op = pa_context_set_sink_input_mute(c->context,
|
||||
pa_stream_get_index (pa->stream),
|
||||
sw->vol.mute, NULL, NULL);
|
||||
if (!op) {
|
||||
qpa_logerr (pa_context_errno (g->context),
|
||||
"set_sink_input_mute() failed\n");
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"set_sink_input_mute() failed\n");
|
||||
} else {
|
||||
pa_operation_unref (op);
|
||||
pa_operation_unref(op);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -766,7 +792,7 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||
pa_operation *op;
|
||||
pa_cvolume v;
|
||||
paaudio *g = pa->g;
|
||||
PAConnection *c = pa->g->conn;
|
||||
|
||||
#ifdef PA_CHECK_VERSION
|
||||
pa_cvolume_init (&v);
|
||||
@ -786,29 +812,29 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||
v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
|
||||
v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
|
||||
|
||||
pa_threaded_mainloop_lock (g->mainloop);
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
op = pa_context_set_source_output_volume (g->context,
|
||||
pa_stream_get_index (pa->stream),
|
||||
op = pa_context_set_source_output_volume(c->context,
|
||||
pa_stream_get_index(pa->stream),
|
||||
&v, NULL, NULL);
|
||||
if (!op) {
|
||||
qpa_logerr (pa_context_errno (g->context),
|
||||
"set_source_output_volume() failed\n");
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"set_source_output_volume() failed\n");
|
||||
} else {
|
||||
pa_operation_unref(op);
|
||||
}
|
||||
|
||||
op = pa_context_set_source_output_mute (g->context,
|
||||
op = pa_context_set_source_output_mute(c->context,
|
||||
pa_stream_get_index (pa->stream),
|
||||
sw->vol.mute, NULL, NULL);
|
||||
if (!op) {
|
||||
qpa_logerr (pa_context_errno (g->context),
|
||||
"set_source_output_mute() failed\n");
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"set_source_output_mute() failed\n");
|
||||
} else {
|
||||
pa_operation_unref (op);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -828,11 +854,75 @@ static int qpa_validate_per_direction_opts(Audiodev *dev,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* common */
|
||||
static void *qpa_conn_init(const char *server)
|
||||
{
|
||||
PAConnection *c = g_malloc0(sizeof(PAConnection));
|
||||
QTAILQ_INSERT_TAIL(&pa_conns, c, list);
|
||||
|
||||
c->mainloop = pa_threaded_mainloop_new();
|
||||
if (!c->mainloop) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop),
|
||||
server);
|
||||
if (!c->context) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_context_set_state_callback(c->context, context_state_cb, c);
|
||||
|
||||
if (pa_context_connect(c->context, server, 0, NULL) < 0) {
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"pa_context_connect() failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
if (pa_threaded_mainloop_start(c->mainloop) < 0) {
|
||||
goto unlock_and_fail;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
pa_context_state_t state;
|
||||
|
||||
state = pa_context_get_state(c->context);
|
||||
|
||||
if (state == PA_CONTEXT_READY) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!PA_CONTEXT_IS_GOOD(state)) {
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"Wrong context state\n");
|
||||
goto unlock_and_fail;
|
||||
}
|
||||
|
||||
/* Wait until the context is ready */
|
||||
pa_threaded_mainloop_wait(c->mainloop);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return c;
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
fail:
|
||||
AUD_log (AUDIO_CAP, "Failed to initialize PA context");
|
||||
qpa_conn_fini(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *qpa_audio_init(Audiodev *dev)
|
||||
{
|
||||
paaudio *g;
|
||||
AudiodevPaOptions *popts = &dev->u.pa;
|
||||
const char *server;
|
||||
PAConnection *c;
|
||||
|
||||
assert(dev->driver == AUDIODEV_DRIVER_PA);
|
||||
|
||||
if (!popts->has_server) {
|
||||
char pidfile[64];
|
||||
@ -849,93 +939,64 @@ static void *qpa_audio_init(Audiodev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
assert(dev->driver == AUDIODEV_DRIVER_PA);
|
||||
|
||||
g = g_malloc(sizeof(paaudio));
|
||||
server = popts->has_server ? popts->server : NULL;
|
||||
|
||||
if (!qpa_validate_per_direction_opts(dev, popts->in)) {
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
if (!qpa_validate_per_direction_opts(dev, popts->out)) {
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g = g_malloc0(sizeof(paaudio));
|
||||
server = popts->has_server ? popts->server : NULL;
|
||||
|
||||
g->dev = dev;
|
||||
g->mainloop = NULL;
|
||||
g->context = NULL;
|
||||
|
||||
g->mainloop = pa_threaded_mainloop_new ();
|
||||
if (!g->mainloop) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
|
||||
server);
|
||||
if (!g->context) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_context_set_state_callback (g->context, context_state_cb, g);
|
||||
|
||||
if (pa_context_connect(g->context, server, 0, NULL) < 0) {
|
||||
qpa_logerr (pa_context_errno (g->context),
|
||||
"pa_context_connect() failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock (g->mainloop);
|
||||
|
||||
if (pa_threaded_mainloop_start (g->mainloop) < 0) {
|
||||
goto unlock_and_fail;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
pa_context_state_t state;
|
||||
|
||||
state = pa_context_get_state (g->context);
|
||||
|
||||
if (state == PA_CONTEXT_READY) {
|
||||
QTAILQ_FOREACH(c, &pa_conns, list) {
|
||||
if (server == NULL || c->server == NULL ?
|
||||
server == c->server :
|
||||
strcmp(server, c->server) == 0) {
|
||||
g->conn = c;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!PA_CONTEXT_IS_GOOD (state)) {
|
||||
qpa_logerr (pa_context_errno (g->context),
|
||||
"Wrong context state\n");
|
||||
goto unlock_and_fail;
|
||||
}
|
||||
|
||||
/* Wait until the context is ready */
|
||||
pa_threaded_mainloop_wait (g->mainloop);
|
||||
}
|
||||
if (!g->conn) {
|
||||
g->conn = qpa_conn_init(server);
|
||||
}
|
||||
if (!g->conn) {
|
||||
g_free(g);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
|
||||
++g->conn->refcount;
|
||||
return g;
|
||||
}
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock (g->mainloop);
|
||||
fail:
|
||||
AUD_log (AUDIO_CAP, "Failed to initialize PA context");
|
||||
qpa_audio_fini(g);
|
||||
return NULL;
|
||||
static void qpa_conn_fini(PAConnection *c)
|
||||
{
|
||||
if (c->mainloop) {
|
||||
pa_threaded_mainloop_stop(c->mainloop);
|
||||
}
|
||||
|
||||
if (c->context) {
|
||||
pa_context_disconnect(c->context);
|
||||
pa_context_unref(c->context);
|
||||
}
|
||||
|
||||
if (c->mainloop) {
|
||||
pa_threaded_mainloop_free(c->mainloop);
|
||||
}
|
||||
|
||||
QTAILQ_REMOVE(&pa_conns, c, list);
|
||||
g_free(c);
|
||||
}
|
||||
|
||||
static void qpa_audio_fini (void *opaque)
|
||||
{
|
||||
paaudio *g = opaque;
|
||||
PAConnection *c = g->conn;
|
||||
|
||||
if (g->mainloop) {
|
||||
pa_threaded_mainloop_stop (g->mainloop);
|
||||
}
|
||||
|
||||
if (g->context) {
|
||||
pa_context_disconnect (g->context);
|
||||
pa_context_unref (g->context);
|
||||
}
|
||||
|
||||
if (g->mainloop) {
|
||||
pa_threaded_mainloop_free (g->mainloop);
|
||||
if (--c->refcount == 0) {
|
||||
qpa_conn_fini(c);
|
||||
}
|
||||
|
||||
g_free(g);
|
||||
@ -945,13 +1006,11 @@ static struct audio_pcm_ops qpa_pcm_ops = {
|
||||
.init_out = qpa_init_out,
|
||||
.fini_out = qpa_fini_out,
|
||||
.run_out = qpa_run_out,
|
||||
.write = qpa_write,
|
||||
.ctl_out = qpa_ctl_out,
|
||||
|
||||
.init_in = qpa_init_in,
|
||||
.fini_in = qpa_fini_in,
|
||||
.run_in = qpa_run_in,
|
||||
.read = qpa_read,
|
||||
.ctl_in = qpa_ctl_in
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
* Return number of samples processed.
|
||||
*/
|
||||
void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
||||
int *isamp, int *osamp)
|
||||
size_t *isamp, size_t *osamp)
|
||||
{
|
||||
struct rate *rate = opaque;
|
||||
struct st_sample *istart, *iend;
|
||||
|
@ -41,8 +41,8 @@
|
||||
|
||||
typedef struct SDLVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
int live;
|
||||
int decr;
|
||||
size_t live;
|
||||
size_t decr;
|
||||
} SDLVoiceOut;
|
||||
|
||||
static struct SDLAudioState {
|
||||
@ -184,22 +184,22 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
SDLVoiceOut *sdl = opaque;
|
||||
SDLAudioState *s = &glob_sdl;
|
||||
HWVoiceOut *hw = &sdl->hw;
|
||||
int samples = len >> hw->info.shift;
|
||||
int to_mix, decr;
|
||||
size_t samples = len >> hw->info.shift;
|
||||
size_t to_mix, decr;
|
||||
|
||||
if (s->exit || !sdl->live) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* dolog ("in callback samples=%d live=%d\n", samples, sdl->live); */
|
||||
/* dolog ("in callback samples=%zu live=%zu\n", samples, sdl->live); */
|
||||
|
||||
to_mix = audio_MIN(samples, sdl->live);
|
||||
to_mix = MIN(samples, sdl->live);
|
||||
decr = to_mix;
|
||||
while (to_mix) {
|
||||
int chunk = audio_MIN(to_mix, hw->samples - hw->rpos);
|
||||
size_t chunk = MIN(to_mix, hw->samples - hw->rpos);
|
||||
struct st_sample *src = hw->mix_buf + hw->rpos;
|
||||
|
||||
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
|
||||
/* dolog ("in callback to_mix %zu, chunk %zu\n", to_mix, chunk); */
|
||||
hw->clip(buf, src, chunk);
|
||||
hw->rpos = (hw->rpos + chunk) % hw->samples;
|
||||
to_mix -= chunk;
|
||||
@ -209,7 +209,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
sdl->live -= decr;
|
||||
sdl->decr += decr;
|
||||
|
||||
/* dolog ("done len=%d\n", len); */
|
||||
/* dolog ("done len=%zu\n", len); */
|
||||
|
||||
/* SDL2 does not clear the remaining buffer for us, so do it on our own */
|
||||
if (samples) {
|
||||
@ -217,14 +217,9 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
|
||||
static size_t sdl_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
static int sdl_run_out (HWVoiceOut *hw, int live)
|
||||
{
|
||||
int decr;
|
||||
size_t decr;
|
||||
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
||||
|
||||
SDL_LockAudio();
|
||||
@ -236,7 +231,7 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
|
||||
sdl->live);
|
||||
}
|
||||
|
||||
decr = audio_MIN (sdl->decr, live);
|
||||
decr = MIN (sdl->decr, live);
|
||||
sdl->decr -= decr;
|
||||
|
||||
sdl->live = live;
|
||||
@ -342,7 +337,6 @@ static struct audio_pcm_ops sdl_pcm_ops = {
|
||||
.init_out = sdl_init_out,
|
||||
.fini_out = sdl_fini_out,
|
||||
.run_out = sdl_run_out,
|
||||
.write = sdl_write_out,
|
||||
.ctl_out = sdl_ctl_out,
|
||||
};
|
||||
|
||||
|
@ -152,31 +152,31 @@ static void line_out_fini (HWVoiceOut *hw)
|
||||
spice_server_remove_interface (&out->sin.base);
|
||||
}
|
||||
|
||||
static int line_out_run (HWVoiceOut *hw, int live)
|
||||
static size_t line_out_run (HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
|
||||
int rpos, decr;
|
||||
int samples;
|
||||
size_t rpos, decr;
|
||||
size_t samples;
|
||||
|
||||
if (!live) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
decr = rate_get_samples (&hw->info, &out->rate);
|
||||
decr = audio_MIN (live, decr);
|
||||
decr = MIN (live, decr);
|
||||
|
||||
samples = decr;
|
||||
rpos = hw->rpos;
|
||||
while (samples) {
|
||||
int left_till_end_samples = hw->samples - rpos;
|
||||
int len = audio_MIN (samples, left_till_end_samples);
|
||||
int len = MIN (samples, left_till_end_samples);
|
||||
|
||||
if (!out->frame) {
|
||||
spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
|
||||
out->fpos = out->frame;
|
||||
}
|
||||
if (out->frame) {
|
||||
len = audio_MIN (len, out->fsize);
|
||||
len = MIN (len, out->fsize);
|
||||
hw->clip (out->fpos, hw->mix_buf + rpos, len);
|
||||
out->fsize -= len;
|
||||
out->fpos += len;
|
||||
@ -192,11 +192,6 @@ static int line_out_run (HWVoiceOut *hw, int live)
|
||||
return decr;
|
||||
}
|
||||
|
||||
static int line_out_write (SWVoiceOut *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
|
||||
{
|
||||
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
|
||||
@ -280,12 +275,12 @@ static void line_in_fini (HWVoiceIn *hw)
|
||||
spice_server_remove_interface (&in->sin.base);
|
||||
}
|
||||
|
||||
static int line_in_run (HWVoiceIn *hw)
|
||||
static size_t line_in_run(HWVoiceIn *hw)
|
||||
{
|
||||
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
|
||||
int num_samples;
|
||||
size_t num_samples;
|
||||
int ready;
|
||||
int len[2];
|
||||
size_t len[2];
|
||||
uint64_t delta_samp;
|
||||
const uint32_t *samples;
|
||||
|
||||
@ -294,7 +289,7 @@ static int line_in_run (HWVoiceIn *hw)
|
||||
}
|
||||
|
||||
delta_samp = rate_get_samples (&hw->info, &in->rate);
|
||||
num_samples = audio_MIN (num_samples, delta_samp);
|
||||
num_samples = MIN (num_samples, delta_samp);
|
||||
|
||||
ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
|
||||
samples = in->samples;
|
||||
@ -304,7 +299,7 @@ static int line_in_run (HWVoiceIn *hw)
|
||||
ready = LINE_IN_SAMPLES;
|
||||
}
|
||||
|
||||
num_samples = audio_MIN (ready, num_samples);
|
||||
num_samples = MIN (ready, num_samples);
|
||||
|
||||
if (hw->wpos + num_samples > hw->samples) {
|
||||
len[0] = hw->samples - hw->wpos;
|
||||
@ -325,11 +320,6 @@ static int line_in_run (HWVoiceIn *hw)
|
||||
return num_samples;
|
||||
}
|
||||
|
||||
static int line_in_read (SWVoiceIn *sw, void *buf, int size)
|
||||
{
|
||||
return audio_pcm_sw_read (sw, buf, size);
|
||||
}
|
||||
|
||||
static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
|
||||
{
|
||||
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
|
||||
@ -377,13 +367,11 @@ static struct audio_pcm_ops audio_callbacks = {
|
||||
.init_out = line_out_init,
|
||||
.fini_out = line_out_fini,
|
||||
.run_out = line_out_run,
|
||||
.write = line_out_write,
|
||||
.ctl_out = line_out_ctl,
|
||||
|
||||
.init_in = line_in_init,
|
||||
.fini_in = line_in_fini,
|
||||
.run_in = line_in_run,
|
||||
.read = line_in_read,
|
||||
.ctl_in = line_in_ctl,
|
||||
};
|
||||
|
||||
|
@ -40,10 +40,10 @@ typedef struct WAVVoiceOut {
|
||||
int total_samples;
|
||||
} WAVVoiceOut;
|
||||
|
||||
static int wav_run_out (HWVoiceOut *hw, int live)
|
||||
static size_t wav_run_out(HWVoiceOut *hw, size_t live)
|
||||
{
|
||||
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
|
||||
int rpos, decr, samples;
|
||||
size_t rpos, decr, samples;
|
||||
uint8_t *dst;
|
||||
struct st_sample *src;
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
@ -59,12 +59,12 @@ static int wav_run_out (HWVoiceOut *hw, int live)
|
||||
}
|
||||
|
||||
wav->old_ticks = now;
|
||||
decr = audio_MIN (live, samples);
|
||||
decr = MIN (live, samples);
|
||||
samples = decr;
|
||||
rpos = hw->rpos;
|
||||
while (samples) {
|
||||
int left_till_end_samples = hw->samples - rpos;
|
||||
int convert_samples = audio_MIN (samples, left_till_end_samples);
|
||||
int convert_samples = MIN (samples, left_till_end_samples);
|
||||
|
||||
src = hw->mix_buf + rpos;
|
||||
dst = advance (wav->pcm_buf, rpos << hw->info.shift);
|
||||
@ -84,11 +84,6 @@ static int wav_run_out (HWVoiceOut *hw, int live)
|
||||
return decr;
|
||||
}
|
||||
|
||||
static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
|
||||
{
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
/* VICE code: Store number as little endian. */
|
||||
static void le_store (uint8_t *buf, uint32_t val, int len)
|
||||
{
|
||||
@ -144,8 +139,8 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
hw->samples = 1024;
|
||||
wav->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||
if (!wav->pcm_buf) {
|
||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
||||
hw->samples << hw->info.shift);
|
||||
dolog("Could not allocate buffer (%zu bytes)\n",
|
||||
hw->samples << hw->info.shift);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -240,7 +235,6 @@ static struct audio_pcm_ops wav_pcm_ops = {
|
||||
.init_out = wav_init_out,
|
||||
.fini_out = wav_fini_out,
|
||||
.run_out = wav_run_out,
|
||||
.write = wav_write_out,
|
||||
.ctl_out = wav_ctl_out,
|
||||
};
|
||||
|
||||
|
@ -104,8 +104,8 @@ static struct capture_ops wav_capture_ops = {
|
||||
.info = wav_capture_info
|
||||
};
|
||||
|
||||
int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||
int bits, int nchannels)
|
||||
int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
|
||||
int freq, int bits, int nchannels)
|
||||
{
|
||||
WAVState *wav;
|
||||
uint8_t hdr[] = {
|
||||
@ -170,7 +170,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
cap = AUD_add_capture (&as, &ops, wav);
|
||||
cap = AUD_add_capture(state, &as, &ops, wav);
|
||||
if (!cap) {
|
||||
error_report("Failed to add audio capture");
|
||||
goto error_free;
|
||||
|
@ -819,16 +819,17 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "wavcapture",
|
||||
.args_type = "path:F,freq:i?,bits:i?,nchannels:i?",
|
||||
.params = "path [frequency [bits [channels]]]",
|
||||
.args_type = "path:F,audiodev:s,freq:i?,bits:i?,nchannels:i?",
|
||||
.params = "path audiodev [frequency [bits [channels]]]",
|
||||
.help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)",
|
||||
.cmd = hmp_wavcapture,
|
||||
},
|
||||
STEXI
|
||||
@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]]
|
||||
@item wavcapture @var{filename} @var{audiodev} [@var{frequency} [@var{bits} [@var{channels}]]]
|
||||
@findex wavcapture
|
||||
Capture audio into @var{filename}. Using sample rate @var{frequency}
|
||||
bits per sample @var{bits} and number of channels @var{channels}.
|
||||
Capture audio into @var{filename} from @var{audiodev}, using sample rate
|
||||
@var{frequency} bits per sample @var{bits} and number of channels
|
||||
@var{channels}.
|
||||
|
||||
Defaults:
|
||||
@itemize @minus
|
||||
|
@ -965,7 +965,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
||||
uint32_t temp = r->picb << 1;
|
||||
uint32_t written = 0;
|
||||
int to_copy = 0;
|
||||
temp = audio_MIN (temp, max);
|
||||
temp = MIN (temp, max);
|
||||
|
||||
if (!temp) {
|
||||
*stop = 1;
|
||||
@ -974,7 +974,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
||||
|
||||
while (temp) {
|
||||
int copied;
|
||||
to_copy = audio_MIN (temp, sizeof (tmpbuf));
|
||||
to_copy = MIN (temp, sizeof (tmpbuf));
|
||||
pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
|
||||
copied = AUD_write (s->voice_po, tmpbuf, to_copy);
|
||||
dolog ("write_audio max=%x to_copy=%x copied=%x\n",
|
||||
@ -1020,7 +1020,7 @@ static void write_bup (AC97LinkState *s, int elapsed)
|
||||
}
|
||||
|
||||
while (elapsed) {
|
||||
int temp = audio_MIN (elapsed, sizeof (s->silence));
|
||||
int temp = MIN (elapsed, sizeof (s->silence));
|
||||
while (temp) {
|
||||
int copied = AUD_write (s->voice_po, s->silence, temp);
|
||||
if (!copied)
|
||||
@ -1041,7 +1041,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
||||
int to_copy = 0;
|
||||
SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
|
||||
|
||||
temp = audio_MIN (temp, max);
|
||||
temp = MIN (temp, max);
|
||||
|
||||
if (!temp) {
|
||||
*stop = 1;
|
||||
@ -1050,7 +1050,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
||||
|
||||
while (temp) {
|
||||
int acquired;
|
||||
to_copy = audio_MIN (temp, sizeof (tmpbuf));
|
||||
to_copy = MIN (temp, sizeof (tmpbuf));
|
||||
acquired = AUD_read (voice, tmpbuf, to_copy);
|
||||
if (!acquired) {
|
||||
*stop = 1;
|
||||
@ -1410,6 +1410,7 @@ static int ac97_init (PCIBus *bus)
|
||||
}
|
||||
|
||||
static Property ac97_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(AC97LinkState, card),
|
||||
DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
|
||||
DEFINE_PROP_END_OF_LIST (),
|
||||
};
|
||||
|
@ -195,7 +195,7 @@ static void adlib_callback (void *opaque, int free)
|
||||
return;
|
||||
}
|
||||
|
||||
to_play = audio_MIN (s->left, samples);
|
||||
to_play = MIN (s->left, samples);
|
||||
while (to_play) {
|
||||
written = write_audio (s, to_play);
|
||||
|
||||
@ -210,7 +210,7 @@ static void adlib_callback (void *opaque, int free)
|
||||
}
|
||||
}
|
||||
|
||||
samples = audio_MIN (samples, s->samples - s->pos);
|
||||
samples = MIN (samples, s->samples - s->pos);
|
||||
if (!samples) {
|
||||
return;
|
||||
}
|
||||
@ -299,6 +299,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
static Property adlib_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(AdlibState, card),
|
||||
DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220),
|
||||
DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100),
|
||||
DEFINE_PROP_END_OF_LIST (),
|
||||
|
@ -536,7 +536,7 @@ static int cs_write_audio (CSState *s, int nchan, int dma_pos,
|
||||
int copied;
|
||||
size_t to_copy;
|
||||
|
||||
to_copy = audio_MIN (temp, left);
|
||||
to_copy = MIN (temp, left);
|
||||
if (to_copy > sizeof (tmpbuf)) {
|
||||
to_copy = sizeof (tmpbuf);
|
||||
}
|
||||
@ -579,7 +579,7 @@ static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
|
||||
till = (s->dregs[Playback_Lower_Base_Count]
|
||||
| (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
|
||||
till -= s->transferred;
|
||||
copy = audio_MIN (till, copy);
|
||||
copy = MIN (till, copy);
|
||||
}
|
||||
|
||||
if ((copy <= 0) || (dma_len <= 0)) {
|
||||
@ -690,6 +690,7 @@ static int cs4231a_init (ISABus *bus)
|
||||
}
|
||||
|
||||
static Property cs4231a_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(CSState, card),
|
||||
DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
|
||||
DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
|
||||
DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
|
||||
|
@ -645,7 +645,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
||||
int size = d->frame_cnt & 0xffff;
|
||||
int left = ((size - cnt + 1) << 2) + d->leftover;
|
||||
int transferred = 0;
|
||||
int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
|
||||
int temp = MIN (max, MIN (left, csc_bytes));
|
||||
int index = d - &s->chan[0];
|
||||
|
||||
addr += (cnt << 2) + d->leftover;
|
||||
@ -654,7 +654,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
||||
while (temp) {
|
||||
int acquired, to_copy;
|
||||
|
||||
to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
|
||||
to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
|
||||
acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
|
||||
if (!acquired)
|
||||
break;
|
||||
@ -672,7 +672,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
||||
while (temp) {
|
||||
int copied, to_copy;
|
||||
|
||||
to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
|
||||
to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
|
||||
pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
|
||||
copied = AUD_write (voice, tmpbuf, to_copy);
|
||||
if (!copied)
|
||||
@ -887,6 +887,11 @@ static int es1370_init (PCIBus *bus)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property es1370_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(ES1370State, card),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void es1370_class_init (ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS (klass);
|
||||
@ -903,6 +908,7 @@ static void es1370_class_init (ObjectClass *klass, void *data)
|
||||
dc->desc = "ENSONIQ AudioPCI ES1370";
|
||||
dc->vmsd = &vmstate_es1370;
|
||||
dc->reset = es1370_on_reset;
|
||||
dc->props = es1370_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo es1370_info = {
|
||||
@ -923,4 +929,3 @@ static void es1370_register_types (void)
|
||||
}
|
||||
|
||||
type_init (es1370_register_types)
|
||||
|
||||
|
@ -119,7 +119,7 @@ static void GUS_callback (void *opaque, int free)
|
||||
GUSState *s = opaque;
|
||||
|
||||
samples = free >> s->shift;
|
||||
to_play = audio_MIN (samples, s->left);
|
||||
to_play = MIN (samples, s->left);
|
||||
|
||||
while (to_play) {
|
||||
int written = write_audio (s, to_play);
|
||||
@ -134,7 +134,7 @@ static void GUS_callback (void *opaque, int free)
|
||||
net += written;
|
||||
}
|
||||
|
||||
samples = audio_MIN (samples, s->samples);
|
||||
samples = MIN (samples, s->samples);
|
||||
if (samples) {
|
||||
gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
|
||||
|
||||
@ -194,7 +194,7 @@ static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
|
||||
ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
|
||||
mode = k->has_autoinitialization(s->isa_dma, s->emu.gusdma);
|
||||
while (left) {
|
||||
int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
|
||||
int to_copy = MIN ((size_t) left, sizeof (tmpbuf));
|
||||
int copied;
|
||||
|
||||
ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
|
||||
@ -299,6 +299,7 @@ static int GUS_init (ISABus *bus)
|
||||
}
|
||||
|
||||
static Property gus_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(GUSState, card),
|
||||
DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
|
||||
DEFINE_PROP_UINT32 ("iobase", GUSState, port, 0x240),
|
||||
DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
|
||||
|
@ -235,10 +235,10 @@ static void hda_audio_input_timer(void *opaque)
|
||||
goto out_timer;
|
||||
}
|
||||
|
||||
int64_t to_transfer = audio_MIN(wpos - rpos, wanted_rpos - rpos);
|
||||
int64_t to_transfer = MIN(wpos - rpos, wanted_rpos - rpos);
|
||||
while (to_transfer) {
|
||||
uint32_t start = (rpos & B_MASK);
|
||||
uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer);
|
||||
uint32_t chunk = MIN(B_SIZE - start, to_transfer);
|
||||
int rc = hda_codec_xfer(
|
||||
&st->state->hda, st->stream, false, st->buf + start, chunk);
|
||||
if (!rc) {
|
||||
@ -263,13 +263,13 @@ static void hda_audio_input_cb(void *opaque, int avail)
|
||||
int64_t wpos = st->wpos;
|
||||
int64_t rpos = st->rpos;
|
||||
|
||||
int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail);
|
||||
int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), avail);
|
||||
|
||||
hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1)));
|
||||
|
||||
while (to_transfer) {
|
||||
uint32_t start = (uint32_t) (wpos & B_MASK);
|
||||
uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer);
|
||||
uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
|
||||
uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk);
|
||||
wpos += read;
|
||||
to_transfer -= read;
|
||||
@ -299,10 +299,10 @@ static void hda_audio_output_timer(void *opaque)
|
||||
goto out_timer;
|
||||
}
|
||||
|
||||
int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos);
|
||||
int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos);
|
||||
while (to_transfer) {
|
||||
uint32_t start = (wpos & B_MASK);
|
||||
uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer);
|
||||
uint32_t chunk = MIN(B_SIZE - start, to_transfer);
|
||||
int rc = hda_codec_xfer(
|
||||
&st->state->hda, st->stream, true, st->buf + start, chunk);
|
||||
if (!rc) {
|
||||
@ -327,7 +327,7 @@ static void hda_audio_output_cb(void *opaque, int avail)
|
||||
int64_t wpos = st->wpos;
|
||||
int64_t rpos = st->rpos;
|
||||
|
||||
int64_t to_transfer = audio_MIN(wpos - rpos, avail);
|
||||
int64_t to_transfer = MIN(wpos - rpos, avail);
|
||||
|
||||
if (wpos - rpos == B_SIZE) {
|
||||
/* drop buffer, reset timer adjust */
|
||||
@ -342,7 +342,7 @@ static void hda_audio_output_cb(void *opaque, int avail)
|
||||
|
||||
while (to_transfer) {
|
||||
uint32_t start = (uint32_t) (rpos & B_MASK);
|
||||
uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer);
|
||||
uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
|
||||
uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk);
|
||||
rpos += written;
|
||||
to_transfer -= written;
|
||||
@ -841,6 +841,7 @@ static const VMStateDescription vmstate_hda_audio = {
|
||||
};
|
||||
|
||||
static Property hda_audio_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(HDAAudioState, card),
|
||||
DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
|
||||
DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
|
||||
DEFINE_PROP_BOOL("use-timer", HDAAudioState, use_timer, true),
|
||||
|
@ -185,7 +185,7 @@ static void ac97_in_cb(void *opaque, int avail_b)
|
||||
MilkymistAC97State *s = opaque;
|
||||
uint8_t buf[4096];
|
||||
uint32_t remaining = s->regs[R_U_REMAINING];
|
||||
int temp = audio_MIN(remaining, avail_b);
|
||||
int temp = MIN(remaining, avail_b);
|
||||
uint32_t addr = s->regs[R_U_ADDR];
|
||||
int transferred = 0;
|
||||
|
||||
@ -199,7 +199,7 @@ static void ac97_in_cb(void *opaque, int avail_b)
|
||||
while (temp) {
|
||||
int acquired, to_copy;
|
||||
|
||||
to_copy = audio_MIN(temp, sizeof(buf));
|
||||
to_copy = MIN(temp, sizeof(buf));
|
||||
acquired = AUD_read(s->voice_in, buf, to_copy);
|
||||
if (!acquired) {
|
||||
break;
|
||||
@ -228,7 +228,7 @@ static void ac97_out_cb(void *opaque, int free_b)
|
||||
MilkymistAC97State *s = opaque;
|
||||
uint8_t buf[4096];
|
||||
uint32_t remaining = s->regs[R_D_REMAINING];
|
||||
int temp = audio_MIN(remaining, free_b);
|
||||
int temp = MIN(remaining, free_b);
|
||||
uint32_t addr = s->regs[R_D_ADDR];
|
||||
int transferred = 0;
|
||||
|
||||
@ -242,7 +242,7 @@ static void ac97_out_cb(void *opaque, int free_b)
|
||||
while (temp) {
|
||||
int copied, to_copy;
|
||||
|
||||
to_copy = audio_MIN(temp, sizeof(buf));
|
||||
to_copy = MIN(temp, sizeof(buf));
|
||||
cpu_physical_memory_read(addr, buf, to_copy);
|
||||
copied = AUD_write(s->voice_out, buf, to_copy);
|
||||
if (!copied) {
|
||||
@ -330,6 +330,11 @@ static const VMStateDescription vmstate_milkymist_ac97 = {
|
||||
}
|
||||
};
|
||||
|
||||
static Property milkymist_ac97_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(MilkymistAC97State, card),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -337,6 +342,7 @@ static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
|
||||
dc->realize = milkymist_ac97_realize;
|
||||
dc->reset = milkymist_ac97_reset;
|
||||
dc->vmsd = &vmstate_milkymist_ac97;
|
||||
dc->props = milkymist_ac97_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo milkymist_ac97_info = {
|
||||
|
@ -103,7 +103,7 @@ static void pcspk_callback(void *opaque, int free)
|
||||
}
|
||||
|
||||
while (free > 0) {
|
||||
n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
|
||||
n = MIN(s->samples - s->play_pos, (unsigned int)free);
|
||||
n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
|
||||
if (!n)
|
||||
break;
|
||||
@ -209,6 +209,7 @@ static const VMStateDescription vmstate_spk = {
|
||||
};
|
||||
|
||||
static Property pcspk_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(PCSpkState, card),
|
||||
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
|
||||
DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
@ -625,6 +625,7 @@ static const VMStateDescription vmstate_pl041 = {
|
||||
};
|
||||
|
||||
static Property pl041_device_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(PL041State, codec.card),
|
||||
/* Non-compact FIFO depth property */
|
||||
DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth,
|
||||
DEFAULT_FIFO_DEPTH),
|
||||
|
@ -1169,7 +1169,7 @@ static int write_audio (SB16State *s, int nchan, int dma_pos,
|
||||
int copied;
|
||||
size_t to_copy;
|
||||
|
||||
to_copy = audio_MIN (temp, left);
|
||||
to_copy = MIN (temp, left);
|
||||
if (to_copy > sizeof (tmpbuf)) {
|
||||
to_copy = sizeof (tmpbuf);
|
||||
}
|
||||
@ -1422,6 +1422,7 @@ static int SB16_init (ISABus *bus)
|
||||
}
|
||||
|
||||
static Property sb16_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(SB16State, card),
|
||||
DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
|
||||
DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
|
||||
DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
|
||||
|
@ -70,7 +70,7 @@ static inline void wm8750_in_load(WM8750State *s)
|
||||
{
|
||||
if (s->idx_in + s->req_in <= sizeof(s->data_in))
|
||||
return;
|
||||
s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
|
||||
s->idx_in = MAX(0, (int) sizeof(s->data_in) - s->req_in);
|
||||
AUD_read(*s->in[0], s->data_in + s->idx_in,
|
||||
sizeof(s->data_in) - s->idx_in);
|
||||
}
|
||||
@ -101,7 +101,7 @@ static void wm8750_audio_out_cb(void *opaque, int free_b)
|
||||
wm8750_out_flush(s);
|
||||
} else
|
||||
s->req_out = free_b - s->idx_out;
|
||||
|
||||
|
||||
s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
|
||||
}
|
||||
|
||||
@ -702,6 +702,11 @@ void wm8750_set_bclk_in(void *opaque, int new_hz)
|
||||
wm8750_clk_update(s, 1);
|
||||
}
|
||||
|
||||
static Property wm8750_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(WM8750State, card),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void wm8750_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -712,6 +717,7 @@ static void wm8750_class_init(ObjectClass *klass, void *data)
|
||||
sc->recv = wm8750_rx;
|
||||
sc->send = wm8750_tx;
|
||||
dc->vmsd = &vmstate_wm8750;
|
||||
dc->props = wm8750_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo wm8750_info = {
|
||||
|
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "audio/audio.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
@ -353,6 +354,62 @@ const PropertyInfo qdev_prop_netdev = {
|
||||
};
|
||||
|
||||
|
||||
/* --- audiodev --- */
|
||||
static void get_audiodev(Object *obj, Visitor *v, const char* name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
|
||||
char *p = g_strdup(audio_get_id(card));
|
||||
|
||||
visit_type_str(v, name, &p, errp);
|
||||
g_free(p);
|
||||
}
|
||||
|
||||
static void set_audiodev(Object *obj, Visitor *v, const char* name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
|
||||
AudioState *state;
|
||||
Error *local_err = NULL;
|
||||
int err = 0;
|
||||
char *str;
|
||||
|
||||
if (dev->realized) {
|
||||
qdev_prop_set_after_realize(dev, name, errp);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_str(v, name, &str, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
state = audio_state_by_name(str);
|
||||
|
||||
if (!state) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
card->state = state;
|
||||
|
||||
out:
|
||||
error_set_from_qdev_prop_error(errp, err, dev, prop, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
const PropertyInfo qdev_prop_audiodev = {
|
||||
.name = "str",
|
||||
.description = "ID of an audiodev to use as a backend",
|
||||
/* release done on shutdown */
|
||||
.get = get_audiodev,
|
||||
.set = set_audiodev,
|
||||
};
|
||||
|
||||
void qdev_prop_set_drive(DeviceState *dev, const char *name,
|
||||
BlockBackend *value, Error **errp)
|
||||
{
|
||||
|
@ -667,6 +667,7 @@ static const VMStateDescription vmstate_usb_audio = {
|
||||
};
|
||||
|
||||
static Property usb_audio_properties[] = {
|
||||
DEFINE_AUDIO_PROPERTIES(USBAudioState, card),
|
||||
DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
|
||||
DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
|
||||
32 * USBAUDIO_PACKET_SIZE),
|
||||
|
@ -33,6 +33,7 @@ extern const PropertyInfo qdev_prop_blocksize;
|
||||
extern const PropertyInfo qdev_prop_pci_host_devaddr;
|
||||
extern const PropertyInfo qdev_prop_uuid;
|
||||
extern const PropertyInfo qdev_prop_arraylen;
|
||||
extern const PropertyInfo qdev_prop_audiodev;
|
||||
extern const PropertyInfo qdev_prop_link;
|
||||
extern const PropertyInfo qdev_prop_off_auto_pcibar;
|
||||
extern const PropertyInfo qdev_prop_pcie_link_speed;
|
||||
@ -234,6 +235,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
|
||||
+ type_check(QemuUUID, typeof_field(_state, _field)), \
|
||||
.set_default = true, \
|
||||
}
|
||||
#define DEFINE_PROP_AUDIODEV(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_audiodev, QEMUSoundCard)
|
||||
|
||||
#define DEFINE_PROP_END_OF_LIST() \
|
||||
{}
|
||||
|
@ -179,9 +179,9 @@ void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
|
||||
/* Audio */
|
||||
|
||||
/*! Saves/restores number of played samples of audio out operation. */
|
||||
void replay_audio_out(int *played);
|
||||
void replay_audio_out(size_t *played);
|
||||
/*! Saves/restores recorded samples of audio in operation. */
|
||||
void replay_audio_in(int *recorded, void *samples, int *wpos, int size);
|
||||
void replay_audio_in(size_t *recorded, void *samples, size_t *wpos, size_t size);
|
||||
|
||||
/* VM state operations */
|
||||
|
||||
|
@ -1142,21 +1142,21 @@ static void hmp_stopcapture(Monitor *mon, const QDict *qdict)
|
||||
static void hmp_wavcapture(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *path = qdict_get_str(qdict, "path");
|
||||
int has_freq = qdict_haskey(qdict, "freq");
|
||||
int freq = qdict_get_try_int(qdict, "freq", -1);
|
||||
int has_bits = qdict_haskey(qdict, "bits");
|
||||
int bits = qdict_get_try_int(qdict, "bits", -1);
|
||||
int has_channels = qdict_haskey(qdict, "nchannels");
|
||||
int nchannels = qdict_get_try_int(qdict, "nchannels", -1);
|
||||
int freq = qdict_get_try_int(qdict, "freq", 44100);
|
||||
int bits = qdict_get_try_int(qdict, "bits", 16);
|
||||
int nchannels = qdict_get_try_int(qdict, "nchannels", 2);
|
||||
const char *audiodev = qdict_get_str(qdict, "audiodev");
|
||||
CaptureState *s;
|
||||
AudioState *as = audio_state_by_name(audiodev);
|
||||
|
||||
if (!as) {
|
||||
monitor_printf(mon, "Audiodev '%s' not found\n", audiodev);
|
||||
return;
|
||||
}
|
||||
|
||||
s = g_malloc0 (sizeof (*s));
|
||||
|
||||
freq = has_freq ? freq : 44100;
|
||||
bits = has_bits ? bits : 16;
|
||||
nchannels = has_channels ? nchannels : 2;
|
||||
|
||||
if (wav_start_capture (s, path, freq, bits, nchannels)) {
|
||||
if (wav_start_capture(as, s, path, freq, bits, nchannels)) {
|
||||
monitor_printf(mon, "Failed to add wave capture\n");
|
||||
g_free (s);
|
||||
return;
|
||||
|
@ -1978,6 +1978,12 @@ can help the device and guest to keep up and not lose events in case
|
||||
events are arriving in bulk. Possible causes for the latter are flaky
|
||||
network connections, or scripts for automated testing.
|
||||
|
||||
@item audiodev=@var{audiodev}
|
||||
|
||||
Use the specified @var{audiodev} when the VNC client requests audio
|
||||
transmission. When not using an -audiodev argument, this option must
|
||||
be omitted, otherwise is must be present and specify a valid audiodev.
|
||||
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
|
@ -15,18 +15,18 @@
|
||||
#include "replay-internal.h"
|
||||
#include "audio/audio.h"
|
||||
|
||||
void replay_audio_out(int *played)
|
||||
void replay_audio_out(size_t *played)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_save_instructions();
|
||||
replay_put_event(EVENT_AUDIO_OUT);
|
||||
replay_put_dword(*played);
|
||||
replay_put_qword(*played);
|
||||
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_account_executed_instructions();
|
||||
if (replay_next_event_is(EVENT_AUDIO_OUT)) {
|
||||
*played = replay_get_dword();
|
||||
*played = replay_get_qword();
|
||||
replay_finish_event();
|
||||
} else {
|
||||
error_report("Missing audio out event in the replay log");
|
||||
@ -35,7 +35,7 @@ void replay_audio_out(int *played)
|
||||
}
|
||||
}
|
||||
|
||||
void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
|
||||
void replay_audio_in(size_t *recorded, void *samples, size_t *wpos, size_t size)
|
||||
{
|
||||
int pos;
|
||||
uint64_t left, right;
|
||||
@ -43,8 +43,8 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_save_instructions();
|
||||
replay_put_event(EVENT_AUDIO_IN);
|
||||
replay_put_dword(*recorded);
|
||||
replay_put_dword(*wpos);
|
||||
replay_put_qword(*recorded);
|
||||
replay_put_qword(*wpos);
|
||||
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
||||
; pos = (pos + 1) % size) {
|
||||
audio_sample_to_uint64(samples, pos, &left, &right);
|
||||
@ -55,8 +55,8 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_account_executed_instructions();
|
||||
if (replay_next_event_is(EVENT_AUDIO_IN)) {
|
||||
*recorded = replay_get_dword();
|
||||
*wpos = replay_get_dword();
|
||||
*recorded = replay_get_qword();
|
||||
*wpos = replay_get_qword();
|
||||
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
||||
; pos = (pos + 1) % size) {
|
||||
left = replay_get_qword();
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
/* Current version of the replay mechanism.
|
||||
Increase it when file format changes. */
|
||||
#define REPLAY_VERSION 0xe02007
|
||||
#define REPLAY_VERSION 0xe02008
|
||||
/* Size of replay log header */
|
||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
||||
|
||||
|
15
ui/vnc.c
15
ui/vnc.c
@ -1224,7 +1224,7 @@ static void audio_add(VncState *vs)
|
||||
ops.destroy = audio_capture_destroy;
|
||||
ops.capture = audio_capture;
|
||||
|
||||
vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
|
||||
vs->audio_cap = AUD_add_capture(vs->vd->audio_state, &vs->as, &ops, vs);
|
||||
if (!vs->audio_cap) {
|
||||
error_report("Failed to add audio capture");
|
||||
}
|
||||
@ -3371,6 +3371,9 @@ static QemuOptsList qemu_vnc_opts = {
|
||||
},{
|
||||
.name = "non-adaptive",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},{
|
||||
.name = "audiodev",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
@ -3808,6 +3811,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
const char *saslauthz;
|
||||
int lock_key_sync = 1;
|
||||
int key_delay_ms;
|
||||
const char *audiodev;
|
||||
|
||||
if (!vd) {
|
||||
error_setg(errp, "VNC display not active");
|
||||
@ -3993,6 +3997,15 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
}
|
||||
vd->ledstate = 0;
|
||||
|
||||
audiodev = qemu_opt_get(opts, "audiodev");
|
||||
if (audiodev) {
|
||||
vd->audio_state = audio_state_by_name(audiodev);
|
||||
if (!vd->audio_state) {
|
||||
error_setg(errp, "Audiodev '%s' not found", audiodev);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
device_id = qemu_opt_get(opts, "display");
|
||||
if (device_id) {
|
||||
int head = qemu_opt_get_number(opts, "head", 0);
|
||||
|
Loading…
Reference in New Issue
Block a user