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;
|
struct pollfd *pfds;
|
||||||
int count;
|
int count;
|
||||||
int mask;
|
int mask;
|
||||||
|
AudioState *s;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ALSAVoiceOut {
|
typedef struct ALSAVoiceOut {
|
||||||
@ -199,11 +200,11 @@ static void alsa_poll_handler (void *opaque)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SND_PCM_STATE_PREPARED:
|
case SND_PCM_STATE_PREPARED:
|
||||||
audio_run ("alsa run (prepared)");
|
audio_run(hlp->s, "alsa run (prepared)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SND_PCM_STATE_RUNNING:
|
case SND_PCM_STATE_RUNNING:
|
||||||
audio_run ("alsa run (running)");
|
audio_run(hlp->s, "alsa run (running)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -269,11 +270,6 @@ static int alsa_poll_in (HWVoiceIn *hw)
|
|||||||
return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
|
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)
|
static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
|
||||||
{
|
{
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
@ -634,7 +630,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
|
|||||||
|
|
||||||
while (alsa->pending) {
|
while (alsa->pending) {
|
||||||
int left_till_end_samples = hw->samples - alsa->wpos;
|
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);
|
char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
|
||||||
|
|
||||||
while (len) {
|
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;
|
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
|
||||||
int decr;
|
size_t decr;
|
||||||
snd_pcm_sframes_t avail;
|
snd_pcm_sframes_t avail;
|
||||||
|
|
||||||
avail = alsa_get_avail (alsa->handle);
|
avail = alsa_get_avail (alsa->handle);
|
||||||
@ -697,7 +693,7 @@ static int alsa_run_out (HWVoiceOut *hw, int live)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
decr = audio_MIN (live, avail);
|
decr = MIN (live, avail);
|
||||||
decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
|
decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
|
||||||
alsa->pending += decr;
|
alsa->pending += decr;
|
||||||
alsa_write_pending (alsa);
|
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);
|
alsa->pcm_buf = audio_calloc(__func__, obt.samples, 1 << hw->info.shift);
|
||||||
if (!alsa->pcm_buf) {
|
if (!alsa->pcm_buf) {
|
||||||
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
|
dolog("Could not allocate DAC buffer (%zu samples, each %d bytes)\n",
|
||||||
hw->samples, 1 << hw->info.shift);
|
hw->samples, 1 << hw->info.shift);
|
||||||
alsa_anal_close1 (&handle);
|
alsa_anal_close1 (&handle);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alsa->pollhlp.s = hw->s;
|
||||||
alsa->handle = handle;
|
alsa->handle = handle;
|
||||||
alsa->dev = dev;
|
alsa->dev = dev;
|
||||||
return 0;
|
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);
|
alsa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||||
if (!alsa->pcm_buf) {
|
if (!alsa->pcm_buf) {
|
||||||
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
|
dolog("Could not allocate ADC buffer (%zu samples, each %d bytes)\n",
|
||||||
hw->samples, 1 << hw->info.shift);
|
hw->samples, 1 << hw->info.shift);
|
||||||
alsa_anal_close1 (&handle);
|
alsa_anal_close1 (&handle);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alsa->pollhlp.s = hw->s;
|
||||||
alsa->handle = handle;
|
alsa->handle = handle;
|
||||||
alsa->dev = dev;
|
alsa->dev = dev;
|
||||||
return 0;
|
return 0;
|
||||||
@ -865,17 +863,17 @@ static void alsa_fini_in (HWVoiceIn *hw)
|
|||||||
alsa->pcm_buf = NULL;
|
alsa->pcm_buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_run_in (HWVoiceIn *hw)
|
static size_t alsa_run_in(HWVoiceIn *hw)
|
||||||
{
|
{
|
||||||
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
||||||
int hwshift = hw->info.shift;
|
int hwshift = hw->info.shift;
|
||||||
int i;
|
int i;
|
||||||
int live = audio_pcm_hw_get_live_in (hw);
|
size_t live = audio_pcm_hw_get_live_in (hw);
|
||||||
int dead = hw->samples - live;
|
size_t dead = hw->samples - live;
|
||||||
int decr;
|
size_t decr;
|
||||||
struct {
|
struct {
|
||||||
int add;
|
size_t add;
|
||||||
int len;
|
size_t len;
|
||||||
} bufs[2] = {
|
} bufs[2] = {
|
||||||
{ .add = hw->wpos, .len = 0 },
|
{ .add = hw->wpos, .len = 0 },
|
||||||
{ .add = 0, .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) {
|
if (!decr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -985,11 +983,6 @@ static int alsa_run_in (HWVoiceIn *hw)
|
|||||||
return read_samples;
|
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, ...)
|
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||||
{
|
{
|
||||||
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
||||||
@ -1073,13 +1066,11 @@ static struct audio_pcm_ops alsa_pcm_ops = {
|
|||||||
.init_out = alsa_init_out,
|
.init_out = alsa_init_out,
|
||||||
.fini_out = alsa_fini_out,
|
.fini_out = alsa_fini_out,
|
||||||
.run_out = alsa_run_out,
|
.run_out = alsa_run_out,
|
||||||
.write = alsa_write,
|
|
||||||
.ctl_out = alsa_ctl_out,
|
.ctl_out = alsa_ctl_out,
|
||||||
|
|
||||||
.init_in = alsa_init_in,
|
.init_in = alsa_init_in,
|
||||||
.fini_in = alsa_fini_in,
|
.fini_in = alsa_fini_in,
|
||||||
.run_in = alsa_run_in,
|
.run_in = alsa_run_in,
|
||||||
.read = alsa_read,
|
|
||||||
.ctl_in = alsa_ctl_in,
|
.ctl_in = alsa_ctl_in,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
335
audio/audio.c
335
audio/audio.c
@ -87,7 +87,8 @@ audio_driver *audio_driver_lookup(const char *name)
|
|||||||
return NULL;
|
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 = {
|
const struct mixeng_volume nominal_volume = {
|
||||||
.mute = 0,
|
.mute = 0,
|
||||||
@ -100,6 +101,8 @@ const struct mixeng_volume nominal_volume = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool legacy_config = true;
|
||||||
|
|
||||||
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
|
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
|
||||||
#error No its not
|
#error No its not
|
||||||
#else
|
#else
|
||||||
@ -306,6 +309,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
|||||||
|
|
||||||
case AUDIO_FORMAT_S16:
|
case AUDIO_FORMAT_S16:
|
||||||
sign = 1;
|
sign = 1;
|
||||||
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U16:
|
case AUDIO_FORMAT_U16:
|
||||||
bits = 16;
|
bits = 16;
|
||||||
shift = 1;
|
shift = 1;
|
||||||
@ -313,6 +317,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
|||||||
|
|
||||||
case AUDIO_FORMAT_S32:
|
case AUDIO_FORMAT_S32:
|
||||||
sign = 1;
|
sign = 1;
|
||||||
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U32:
|
case AUDIO_FORMAT_U32:
|
||||||
bits = 32;
|
bits = 32;
|
||||||
shift = 2;
|
shift = 2;
|
||||||
@ -399,12 +404,10 @@ static void noop_conv (struct st_sample *dst, const void *src, int samples)
|
|||||||
(void) samples;
|
(void) samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CaptureVoiceOut *audio_pcm_capture_find_specific (
|
static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
|
||||||
struct audsettings *as
|
struct audsettings *as)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
CaptureVoiceOut *cap;
|
CaptureVoiceOut *cap;
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
|
|
||||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||||
if (audio_pcm_info_eq (&cap->hw.info, as)) {
|
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)
|
static int audio_attach_capture (HWVoiceOut *hw)
|
||||||
{
|
{
|
||||||
AudioState *s = &glob_audio_state;
|
AudioState *s = hw->s;
|
||||||
CaptureVoiceOut *cap;
|
CaptureVoiceOut *cap;
|
||||||
|
|
||||||
audio_detach_capture (hw);
|
audio_detach_capture (hw);
|
||||||
@ -525,41 +528,41 @@ static int audio_attach_capture (HWVoiceOut *hw)
|
|||||||
/*
|
/*
|
||||||
* Hard voice (capture)
|
* 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;
|
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) {
|
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||||
if (sw->active) {
|
if (sw->active) {
|
||||||
m = audio_MIN (m, sw->total_hw_samples_acquired);
|
m = MIN (m, sw->total_hw_samples_acquired);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m;
|
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);
|
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
||||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
if (audio_bug(__func__, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
return live;
|
return live;
|
||||||
}
|
}
|
||||||
|
|
||||||
int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
|
size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
|
||||||
int live, int pending)
|
size_t live, size_t pending)
|
||||||
{
|
{
|
||||||
int left = hw->samples - pending;
|
size_t left = hw->samples - pending;
|
||||||
int len = audio_MIN (left, live);
|
size_t len = MIN (left, live);
|
||||||
int clipped = 0;
|
size_t clipped = 0;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
struct st_sample *src = hw->mix_buf + hw->rpos;
|
struct st_sample *src = hw->mix_buf + hw->rpos;
|
||||||
uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
|
uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
|
||||||
int samples_till_end_of_buf = hw->samples - hw->rpos;
|
size_t samples_till_end_of_buf = hw->samples - hw->rpos;
|
||||||
int samples_to_clip = audio_MIN (len, samples_till_end_of_buf);
|
size_t samples_to_clip = MIN (len, samples_till_end_of_buf);
|
||||||
|
|
||||||
hw->clip (dst, src, samples_to_clip);
|
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)
|
* 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;
|
HWVoiceIn *hw = sw->hw;
|
||||||
int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
ssize_t live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
int rpos;
|
ssize_t rpos;
|
||||||
|
|
||||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
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;
|
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;
|
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;
|
struct st_sample *src, *dst = sw->buf;
|
||||||
|
|
||||||
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
|
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
|
||||||
|
|
||||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
if (audio_bug(__func__, live > hw->samples)) {
|
||||||
dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
|
dolog("live_in=%zu hw->samples=%zu\n", live, hw->samples);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,13 +616,13 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
swlim = (live * sw->ratio) >> 32;
|
swlim = (live * sw->ratio) >> 32;
|
||||||
swlim = audio_MIN (swlim, samples);
|
swlim = MIN (swlim, samples);
|
||||||
|
|
||||||
while (swlim) {
|
while (swlim) {
|
||||||
src = hw->conv_buf + rpos;
|
src = hw->conv_buf + rpos;
|
||||||
|
if (hw->wpos > rpos) {
|
||||||
isamp = hw->wpos - rpos;
|
isamp = hw->wpos - rpos;
|
||||||
/* XXX: <= ? */
|
} else {
|
||||||
if (isamp <= 0) {
|
|
||||||
isamp = hw->samples - rpos;
|
isamp = hw->samples - rpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,11 +631,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
|||||||
}
|
}
|
||||||
osamp = swlim;
|
osamp = swlim;
|
||||||
|
|
||||||
if (audio_bug(__func__, osamp < 0)) {
|
|
||||||
dolog ("osamp=%d\n", osamp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
|
st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
|
||||||
swlim -= osamp;
|
swlim -= osamp;
|
||||||
rpos = (rpos + isamp) % hw->samples;
|
rpos = (rpos + isamp) % hw->samples;
|
||||||
@ -653,15 +651,15 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
|||||||
/*
|
/*
|
||||||
* Hard voice (playback)
|
* 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;
|
SWVoiceOut *sw;
|
||||||
int m = INT_MAX;
|
size_t m = SIZE_MAX;
|
||||||
int nb_live = 0;
|
int nb_live = 0;
|
||||||
|
|
||||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||||
if (sw->active || !sw->empty) {
|
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;
|
nb_live += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -670,9 +668,9 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
|
|||||||
return m;
|
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;
|
int nb_live1;
|
||||||
|
|
||||||
smin = audio_pcm_hw_find_min_out (hw, &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) {
|
if (nb_live1) {
|
||||||
int live = smin;
|
size_t live = smin;
|
||||||
|
|
||||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
if (audio_bug(__func__, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
return live;
|
return live;
|
||||||
@ -695,10 +693,10 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
|||||||
/*
|
/*
|
||||||
* Soft voice (playback)
|
* 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;
|
size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
|
||||||
int ret = 0, pos = 0, total = 0;
|
size_t ret = 0, pos = 0, total = 0;
|
||||||
|
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
return size;
|
return size;
|
||||||
@ -707,8 +705,8 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
|||||||
hwsamples = sw->hw->samples;
|
hwsamples = sw->hw->samples;
|
||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
live = sw->total_hw_samples_mixed;
|
||||||
if (audio_bug(__func__, live < 0 || live > hwsamples)) {
|
if (audio_bug(__func__, live > hwsamples)) {
|
||||||
dolog ("live=%d hw->samples=%d\n", live, hwsamples);
|
dolog("live=%zu hw->samples=%zu\n", live, hwsamples);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -724,7 +722,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
|||||||
|
|
||||||
dead = hwsamples - live;
|
dead = hwsamples - live;
|
||||||
swlim = ((int64_t) dead << 32) / sw->ratio;
|
swlim = ((int64_t) dead << 32) / sw->ratio;
|
||||||
swlim = audio_MIN (swlim, samples);
|
swlim = MIN (swlim, samples);
|
||||||
if (swlim) {
|
if (swlim) {
|
||||||
sw->conv (sw->buf, buf, swlim);
|
sw->conv (sw->buf, buf, swlim);
|
||||||
|
|
||||||
@ -736,7 +734,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
|||||||
while (swlim) {
|
while (swlim) {
|
||||||
dead = hwsamples - live;
|
dead = hwsamples - live;
|
||||||
left = hwsamples - wpos;
|
left = hwsamples - wpos;
|
||||||
blck = audio_MIN (dead, left);
|
blck = MIN (dead, left);
|
||||||
if (!blck) {
|
if (!blck) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -762,7 +760,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
|||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog (
|
dolog (
|
||||||
"%s: write size %d ret %d total sw %d\n",
|
"%s: write size %zu ret %zu total sw %zu\n",
|
||||||
SW_NAME (sw),
|
SW_NAME (sw),
|
||||||
size >> sw->info.shift,
|
size >> sw->info.shift,
|
||||||
ret,
|
ret,
|
||||||
@ -789,19 +787,15 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
|
|||||||
/*
|
/*
|
||||||
* Timer
|
* Timer
|
||||||
*/
|
*/
|
||||||
|
static int audio_is_timer_needed(AudioState *s)
|
||||||
static bool audio_timer_running;
|
|
||||||
static uint64_t audio_timer_last;
|
|
||||||
|
|
||||||
static int audio_is_timer_needed (void)
|
|
||||||
{
|
{
|
||||||
HWVoiceIn *hwi = NULL;
|
HWVoiceIn *hwi = NULL;
|
||||||
HWVoiceOut *hwo = 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;
|
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;
|
if (!hwi->poll_mode) return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -809,18 +803,18 @@ static int audio_is_timer_needed (void)
|
|||||||
|
|
||||||
static void audio_reset_timer (AudioState *s)
|
static void audio_reset_timer (AudioState *s)
|
||||||
{
|
{
|
||||||
if (audio_is_timer_needed ()) {
|
if (audio_is_timer_needed(s)) {
|
||||||
timer_mod_anticipate_ns(s->ts,
|
timer_mod_anticipate_ns(s->ts,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->period_ticks);
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->period_ticks);
|
||||||
if (!audio_timer_running) {
|
if (!s->timer_running) {
|
||||||
audio_timer_running = true;
|
s->timer_running = true;
|
||||||
audio_timer_last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
s->timer_last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
trace_audio_timer_start(s->period_ticks / SCALE_MS);
|
trace_audio_timer_start(s->period_ticks / SCALE_MS);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
timer_del(s->ts);
|
timer_del(s->ts);
|
||||||
if (audio_timer_running) {
|
if (s->timer_running) {
|
||||||
audio_timer_running = false;
|
s->timer_running = false;
|
||||||
trace_audio_timer_stop();
|
trace_audio_timer_stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -832,20 +826,20 @@ static void audio_timer (void *opaque)
|
|||||||
AudioState *s = opaque;
|
AudioState *s = opaque;
|
||||||
|
|
||||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
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) {
|
if (diff > s->period_ticks * 3 / 2) {
|
||||||
trace_audio_timer_delayed(diff / SCALE_MS);
|
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);
|
audio_reset_timer(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public API
|
* Public API
|
||||||
*/
|
*/
|
||||||
int AUD_write (SWVoiceOut *sw, void *buf, int size)
|
size_t AUD_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
/* XXX: Consider options */
|
/* XXX: Consider options */
|
||||||
@ -857,10 +851,10 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size)
|
|||||||
return 0;
|
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) {
|
if (!sw) {
|
||||||
/* XXX: Consider options */
|
/* XXX: Consider options */
|
||||||
@ -872,7 +866,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size)
|
|||||||
return 0;
|
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)
|
int AUD_get_buffer_size_out (SWVoiceOut *sw)
|
||||||
@ -890,7 +884,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
|||||||
|
|
||||||
hw = sw->hw;
|
hw = sw->hw;
|
||||||
if (sw->active != on) {
|
if (sw->active != on) {
|
||||||
AudioState *s = &glob_audio_state;
|
AudioState *s = sw->s;
|
||||||
SWVoiceOut *temp_sw;
|
SWVoiceOut *temp_sw;
|
||||||
SWVoiceCap *sc;
|
SWVoiceCap *sc;
|
||||||
|
|
||||||
@ -937,7 +931,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
|
|||||||
|
|
||||||
hw = sw->hw;
|
hw = sw->hw;
|
||||||
if (sw->active != on) {
|
if (sw->active != on) {
|
||||||
AudioState *s = &glob_audio_state;
|
AudioState *s = sw->s;
|
||||||
SWVoiceIn *temp_sw;
|
SWVoiceIn *temp_sw;
|
||||||
|
|
||||||
if (on) {
|
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) {
|
if (!sw) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
|
if (audio_bug(__func__, live > sw->hw->samples)) {
|
||||||
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
|
dolog("live=%zu sw->hw->samples=%zu\n", live, sw->hw->samples);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,9 +986,9 @@ static int audio_get_avail (SWVoiceIn *sw)
|
|||||||
return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
|
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) {
|
if (!sw) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -1002,8 +996,8 @@ static int audio_get_free (SWVoiceOut *sw)
|
|||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
live = sw->total_hw_samples_mixed;
|
||||||
|
|
||||||
if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
|
if (audio_bug(__func__, live > sw->hw->samples)) {
|
||||||
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
|
dolog("live=%zu sw->hw->samples=%zu\n", live, sw->hw->samples);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1018,9 +1012,10 @@ static int audio_get_free (SWVoiceOut *sw)
|
|||||||
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
|
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) {
|
if (hw->enabled) {
|
||||||
SWVoiceCap *sc;
|
SWVoiceCap *sc;
|
||||||
@ -1031,16 +1026,16 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
|
|||||||
|
|
||||||
n = samples;
|
n = samples;
|
||||||
while (n) {
|
while (n) {
|
||||||
int till_end_of_hw = hw->samples - rpos2;
|
size_t till_end_of_hw = hw->samples - rpos2;
|
||||||
int to_write = audio_MIN (till_end_of_hw, n);
|
size_t to_write = MIN(till_end_of_hw, n);
|
||||||
int bytes = to_write << hw->info.shift;
|
size_t bytes = to_write << hw->info.shift;
|
||||||
int written;
|
size_t written;
|
||||||
|
|
||||||
sw->buf = hw->mix_buf + rpos2;
|
sw->buf = hw->mix_buf + rpos2;
|
||||||
written = audio_pcm_sw_write (sw, NULL, bytes);
|
written = audio_pcm_sw_write (sw, NULL, bytes);
|
||||||
if (written - bytes) {
|
if (written - bytes) {
|
||||||
dolog ("Could not mix %d bytes into a capture "
|
dolog("Could not mix %zu bytes into a capture "
|
||||||
"buffer, mixed %d\n",
|
"buffer, mixed %zu\n",
|
||||||
bytes, written);
|
bytes, written);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1050,9 +1045,9 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n = audio_MIN (samples, hw->samples - rpos);
|
n = MIN(samples, hw->samples - rpos);
|
||||||
mixeng_clear (hw->mix_buf + rpos, n);
|
mixeng_clear(hw->mix_buf + rpos, n);
|
||||||
mixeng_clear (hw->mix_buf, samples - n);
|
mixeng_clear(hw->mix_buf, samples - n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audio_run_out (AudioState *s)
|
static void audio_run_out (AudioState *s)
|
||||||
@ -1060,17 +1055,17 @@ static void audio_run_out (AudioState *s)
|
|||||||
HWVoiceOut *hw = NULL;
|
HWVoiceOut *hw = NULL;
|
||||||
SWVoiceOut *sw;
|
SWVoiceOut *sw;
|
||||||
|
|
||||||
while ((hw = audio_pcm_hw_find_any_enabled_out (hw))) {
|
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
|
||||||
int played;
|
size_t played, live, prev_rpos, free;
|
||||||
int live, free, nb_live, cleanup_required, prev_rpos;
|
int nb_live, cleanup_required;
|
||||||
|
|
||||||
live = audio_pcm_hw_get_live_out (hw, &nb_live);
|
live = audio_pcm_hw_get_live_out (hw, &nb_live);
|
||||||
if (!nb_live) {
|
if (!nb_live) {
|
||||||
live = 0;
|
live = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, live < 0 || live > hw->samples)) {
|
if (audio_bug(__func__, live > hw->samples)) {
|
||||||
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
|
dolog ("live=%zu hw->samples=%zu\n", live, hw->samples);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,13 +1100,13 @@ static void audio_run_out (AudioState *s)
|
|||||||
played = hw->pcm_ops->run_out (hw, live);
|
played = hw->pcm_ops->run_out (hw, live);
|
||||||
replay_audio_out(&played);
|
replay_audio_out(&played);
|
||||||
if (audio_bug(__func__, hw->rpos >= hw->samples)) {
|
if (audio_bug(__func__, hw->rpos >= hw->samples)) {
|
||||||
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
|
dolog("hw->rpos=%zu hw->samples=%zu played=%zu\n",
|
||||||
hw->rpos, hw->samples, played);
|
hw->rpos, hw->samples, played);
|
||||||
hw->rpos = 0;
|
hw->rpos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog ("played=%d\n", played);
|
dolog("played=%zu\n", played);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (played) {
|
if (played) {
|
||||||
@ -1126,7 +1121,7 @@ static void audio_run_out (AudioState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) {
|
if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) {
|
||||||
dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
|
dolog("played=%zu sw->total_hw_samples_mixed=%zu\n",
|
||||||
played, sw->total_hw_samples_mixed);
|
played, sw->total_hw_samples_mixed);
|
||||||
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;
|
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;
|
SWVoiceIn *sw;
|
||||||
int captured = 0, min;
|
size_t captured = 0, min;
|
||||||
|
|
||||||
if (replay_mode != REPLAY_MODE_PLAY) {
|
if (replay_mode != REPLAY_MODE_PLAY) {
|
||||||
captured = hw->pcm_ops->run_in(hw);
|
captured = hw->pcm_ops->run_in(hw);
|
||||||
@ -1182,7 +1177,7 @@ static void audio_run_in (AudioState *s)
|
|||||||
sw->total_hw_samples_acquired -= min;
|
sw->total_hw_samples_acquired -= min;
|
||||||
|
|
||||||
if (sw->active) {
|
if (sw->active) {
|
||||||
int avail;
|
size_t avail;
|
||||||
|
|
||||||
avail = audio_get_avail (sw);
|
avail = audio_get_avail (sw);
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
@ -1198,15 +1193,15 @@ static void audio_run_capture (AudioState *s)
|
|||||||
CaptureVoiceOut *cap;
|
CaptureVoiceOut *cap;
|
||||||
|
|
||||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
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;
|
HWVoiceOut *hw = &cap->hw;
|
||||||
SWVoiceOut *sw;
|
SWVoiceOut *sw;
|
||||||
|
|
||||||
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
|
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
|
||||||
rpos = hw->rpos;
|
rpos = hw->rpos;
|
||||||
while (live) {
|
while (live) {
|
||||||
int left = hw->samples - rpos;
|
size_t left = hw->samples - rpos;
|
||||||
int to_capture = audio_MIN (live, left);
|
size_t to_capture = MIN(live, left);
|
||||||
struct st_sample *src;
|
struct st_sample *src;
|
||||||
struct capture_callback *cb;
|
struct capture_callback *cb;
|
||||||
|
|
||||||
@ -1229,7 +1224,7 @@ static void audio_run_capture (AudioState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) {
|
if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) {
|
||||||
dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
|
dolog("captured=%zu sw->total_hw_samples_mixed=%zu\n",
|
||||||
captured, sw->total_hw_samples_mixed);
|
captured, sw->total_hw_samples_mixed);
|
||||||
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
|
#ifdef DEBUG_POLL
|
||||||
{
|
{
|
||||||
static double prevtime;
|
static double prevtime;
|
||||||
@ -1271,8 +1265,8 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv,
|
|||||||
s->drv_opaque = drv->init(dev);
|
s->drv_opaque = drv->init(dev);
|
||||||
|
|
||||||
if (s->drv_opaque) {
|
if (s->drv_opaque) {
|
||||||
audio_init_nb_voices_out (drv);
|
audio_init_nb_voices_out(s, drv);
|
||||||
audio_init_nb_voices_in (drv);
|
audio_init_nb_voices_in(s, drv);
|
||||||
s->drv = drv;
|
s->drv = drv;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1293,11 +1287,11 @@ static void audio_vm_change_state_handler (void *opaque, int running,
|
|||||||
int op = running ? VOICE_ENABLE : VOICE_DISABLE;
|
int op = running ? VOICE_ENABLE : VOICE_DISABLE;
|
||||||
|
|
||||||
s->vm_running = running;
|
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);
|
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);
|
hwi->pcm_ops->ctl_in(hwi, op);
|
||||||
}
|
}
|
||||||
audio_reset_timer (s);
|
audio_reset_timer (s);
|
||||||
@ -1310,14 +1304,12 @@ bool audio_is_cleaning_up(void)
|
|||||||
return is_cleaning_up;
|
return is_cleaning_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_cleanup(void)
|
static void free_audio_state(AudioState *s)
|
||||||
{
|
{
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
HWVoiceOut *hwo, *hwon;
|
HWVoiceOut *hwo, *hwon;
|
||||||
HWVoiceIn *hwi, *hwin;
|
HWVoiceIn *hwi, *hwin;
|
||||||
|
|
||||||
is_cleaning_up = true;
|
QLIST_FOREACH_SAFE(hwo, &s->hw_head_out, entries, hwon) {
|
||||||
QLIST_FOREACH_SAFE(hwo, &glob_audio_state.hw_head_out, entries, hwon) {
|
|
||||||
SWVoiceCap *sc;
|
SWVoiceCap *sc;
|
||||||
|
|
||||||
if (hwo->enabled) {
|
if (hwo->enabled) {
|
||||||
@ -1336,7 +1328,7 @@ void audio_cleanup(void)
|
|||||||
QLIST_REMOVE(hwo, entries);
|
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) {
|
if (hwi->enabled) {
|
||||||
hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
|
hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
|
||||||
}
|
}
|
||||||
@ -1353,6 +1345,23 @@ void audio_cleanup(void)
|
|||||||
qapi_free_Audiodev(s->dev);
|
qapi_free_Audiodev(s->dev);
|
||||||
s->dev = NULL;
|
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 = {
|
static const VMStateDescription vmstate_audio = {
|
||||||
@ -1379,28 +1388,34 @@ static AudiodevListEntry *audiodev_find(
|
|||||||
return NULL;
|
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;
|
size_t i;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
const char *drvname = NULL;
|
const char *drvname = NULL;
|
||||||
VMChangeStateEntry *e;
|
VMChangeStateEntry *e;
|
||||||
AudioState *s = &glob_audio_state;
|
AudioState *s;
|
||||||
struct audio_driver *driver;
|
struct audio_driver *driver;
|
||||||
/* silence gcc warning about uninitialized variable */
|
/* silence gcc warning about uninitialized variable */
|
||||||
AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
|
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) {
|
if (dev) {
|
||||||
/* -audiodev option */
|
/* -audiodev option */
|
||||||
|
legacy_config = false;
|
||||||
drvname = AudiodevDriver_str(dev->driver);
|
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 {
|
} else {
|
||||||
/* legacy implicit initialization */
|
/* legacy implicit initialization */
|
||||||
head = audio_handle_legacy_opts();
|
head = audio_handle_legacy_opts();
|
||||||
@ -1414,12 +1429,18 @@ static int audio_init(Audiodev *dev)
|
|||||||
dev = QSIMPLEQ_FIRST(&head)->dev;
|
dev = QSIMPLEQ_FIRST(&head)->dev;
|
||||||
audio_validate_opts(dev, &error_abort);
|
audio_validate_opts(dev, &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s = g_malloc0(sizeof(AudioState));
|
||||||
s->dev = dev;
|
s->dev = dev;
|
||||||
|
|
||||||
QLIST_INIT (&s->hw_head_out);
|
QLIST_INIT (&s->hw_head_out);
|
||||||
QLIST_INIT (&s->hw_head_in);
|
QLIST_INIT (&s->hw_head_in);
|
||||||
QLIST_INIT (&s->cap_head);
|
QLIST_INIT (&s->cap_head);
|
||||||
|
if (!atexit_registered) {
|
||||||
atexit(audio_cleanup);
|
atexit(audio_cleanup);
|
||||||
|
atexit_registered = true;
|
||||||
|
}
|
||||||
|
QTAILQ_INSERT_TAIL(&audio_states, s, list);
|
||||||
|
|
||||||
s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);
|
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);
|
QLIST_INIT (&s->card_head);
|
||||||
vmstate_register (NULL, 0, &vmstate_audio, s);
|
vmstate_register (NULL, 0, &vmstate_audio, s);
|
||||||
return 0;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_free_audiodev_list(AudiodevListHead *head)
|
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)
|
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);
|
card->name = g_strdup (name);
|
||||||
memset (&card->entries, 0, sizeof (card->entries));
|
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)
|
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 audsettings *as,
|
||||||
struct audio_capture_ops *ops,
|
struct audio_capture_ops *ops,
|
||||||
void *cb_opaque
|
void *cb_opaque
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
CaptureVoiceOut *cap;
|
CaptureVoiceOut *cap;
|
||||||
struct capture_callback *cb;
|
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)) {
|
if (audio_validate_settings (as)) {
|
||||||
dolog ("Invalid settings were passed when trying to add capture\n");
|
dolog ("Invalid settings were passed when trying to add capture\n");
|
||||||
audio_print_settings (as);
|
audio_print_settings (as);
|
||||||
@ -1532,7 +1564,7 @@ CaptureVoiceOut *AUD_add_capture (
|
|||||||
cb->ops = *ops;
|
cb->ops = *ops;
|
||||||
cb->opaque = cb_opaque;
|
cb->opaque = cb_opaque;
|
||||||
|
|
||||||
cap = audio_pcm_capture_find_specific (as);
|
cap = audio_pcm_capture_find_specific(s, as);
|
||||||
if (cap) {
|
if (cap) {
|
||||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||||
return cap;
|
return cap;
|
||||||
@ -1544,6 +1576,7 @@ CaptureVoiceOut *AUD_add_capture (
|
|||||||
cap = g_malloc0(sizeof(*cap));
|
cap = g_malloc0(sizeof(*cap));
|
||||||
|
|
||||||
hw = &cap->hw;
|
hw = &cap->hw;
|
||||||
|
hw->s = s;
|
||||||
QLIST_INIT (&hw->sw_head);
|
QLIST_INIT (&hw->sw_head);
|
||||||
QLIST_INIT (&cap->cb_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 (&s->cap_head, cap, entries);
|
||||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, 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);
|
audio_attach_capture (hw);
|
||||||
}
|
}
|
||||||
return cap;
|
return cap;
|
||||||
@ -1749,7 +1782,7 @@ void audio_init_audiodevs(void)
|
|||||||
AudiodevListEntry *e;
|
AudiodevListEntry *e;
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(e, &audiodevs, next) {
|
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) *
|
return audio_buffer_samples(pdo, as, def_usecs) *
|
||||||
audioformat_bytes_per_sample(as->fmt);
|
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 "qemu/queue.h"
|
||||||
#include "qapi/qapi-types-audio.h"
|
#include "qapi/qapi-types-audio.h"
|
||||||
|
#include "hw/qdev-properties.h"
|
||||||
|
|
||||||
typedef void (*audio_callback_fn) (void *opaque, int avail);
|
typedef void (*audio_callback_fn) (void *opaque, int avail);
|
||||||
|
|
||||||
@ -78,8 +79,10 @@ typedef struct SWVoiceOut SWVoiceOut;
|
|||||||
typedef struct CaptureVoiceOut CaptureVoiceOut;
|
typedef struct CaptureVoiceOut CaptureVoiceOut;
|
||||||
typedef struct SWVoiceIn SWVoiceIn;
|
typedef struct SWVoiceIn SWVoiceIn;
|
||||||
|
|
||||||
|
typedef struct AudioState AudioState;
|
||||||
typedef struct QEMUSoundCard {
|
typedef struct QEMUSoundCard {
|
||||||
char *name;
|
char *name;
|
||||||
|
AudioState *state;
|
||||||
QLIST_ENTRY (QEMUSoundCard) entries;
|
QLIST_ENTRY (QEMUSoundCard) entries;
|
||||||
} QEMUSoundCard;
|
} 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_register_card (const char *name, QEMUSoundCard *card);
|
||||||
void AUD_remove_card (QEMUSoundCard *card);
|
void AUD_remove_card (QEMUSoundCard *card);
|
||||||
CaptureVoiceOut *AUD_add_capture (
|
CaptureVoiceOut *AUD_add_capture(
|
||||||
|
AudioState *s,
|
||||||
struct audsettings *as,
|
struct audsettings *as,
|
||||||
struct audio_capture_ops *ops,
|
struct audio_capture_ops *ops,
|
||||||
void *opaque
|
void *opaque
|
||||||
@ -109,7 +113,7 @@ SWVoiceOut *AUD_open_out (
|
|||||||
);
|
);
|
||||||
|
|
||||||
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
|
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);
|
int AUD_get_buffer_size_out (SWVoiceOut *sw);
|
||||||
void AUD_set_active_out (SWVoiceOut *sw, int on);
|
void AUD_set_active_out (SWVoiceOut *sw, int on);
|
||||||
int AUD_is_active_out (SWVoiceOut *sw);
|
int AUD_is_active_out (SWVoiceOut *sw);
|
||||||
@ -130,7 +134,7 @@ SWVoiceIn *AUD_open_in (
|
|||||||
);
|
);
|
||||||
|
|
||||||
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
|
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);
|
void AUD_set_active_in (SWVoiceIn *sw, int on);
|
||||||
int AUD_is_active_in (SWVoiceIn *sw);
|
int AUD_is_active_in (SWVoiceIn *sw);
|
||||||
|
|
||||||
@ -143,25 +147,8 @@ static inline void *advance (void *p, int incr)
|
|||||||
return (d + incr);
|
return (d + incr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __GNUC__
|
int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
|
||||||
#define audio_MIN(a, b) ( __extension__ ({ \
|
int freq, int bits, int nchannels);
|
||||||
__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);
|
|
||||||
|
|
||||||
bool audio_is_cleaning_up(void);
|
bool audio_is_cleaning_up(void);
|
||||||
void audio_cleanup(void);
|
void audio_cleanup(void);
|
||||||
@ -175,4 +162,10 @@ void audio_parse_option(const char *opt);
|
|||||||
void audio_init_audiodevs(void);
|
void audio_init_audiodevs(void);
|
||||||
void audio_legacy_help(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 */
|
#endif /* QEMU_AUDIO_H */
|
||||||
|
@ -49,9 +49,11 @@ struct audio_pcm_info {
|
|||||||
int swap_endianness;
|
int swap_endianness;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct AudioState AudioState;
|
||||||
typedef struct SWVoiceCap SWVoiceCap;
|
typedef struct SWVoiceCap SWVoiceCap;
|
||||||
|
|
||||||
typedef struct HWVoiceOut {
|
typedef struct HWVoiceOut {
|
||||||
|
AudioState *s;
|
||||||
int enabled;
|
int enabled;
|
||||||
int poll_mode;
|
int poll_mode;
|
||||||
int pending_disable;
|
int pending_disable;
|
||||||
@ -59,12 +61,12 @@ typedef struct HWVoiceOut {
|
|||||||
|
|
||||||
f_sample *clip;
|
f_sample *clip;
|
||||||
|
|
||||||
int rpos;
|
size_t rpos;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
struct st_sample *mix_buf;
|
struct st_sample *mix_buf;
|
||||||
|
|
||||||
int samples;
|
size_t samples;
|
||||||
QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
|
QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
|
||||||
QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
|
QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
|
||||||
int ctl_caps;
|
int ctl_caps;
|
||||||
@ -73,19 +75,20 @@ typedef struct HWVoiceOut {
|
|||||||
} HWVoiceOut;
|
} HWVoiceOut;
|
||||||
|
|
||||||
typedef struct HWVoiceIn {
|
typedef struct HWVoiceIn {
|
||||||
|
AudioState *s;
|
||||||
int enabled;
|
int enabled;
|
||||||
int poll_mode;
|
int poll_mode;
|
||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
|
|
||||||
t_sample *conv;
|
t_sample *conv;
|
||||||
|
|
||||||
int wpos;
|
size_t wpos;
|
||||||
int total_samples_captured;
|
size_t total_samples_captured;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
struct st_sample *conv_buf;
|
struct st_sample *conv_buf;
|
||||||
|
|
||||||
int samples;
|
size_t samples;
|
||||||
QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
|
QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
|
||||||
int ctl_caps;
|
int ctl_caps;
|
||||||
struct audio_pcm_ops *pcm_ops;
|
struct audio_pcm_ops *pcm_ops;
|
||||||
@ -94,12 +97,13 @@ typedef struct HWVoiceIn {
|
|||||||
|
|
||||||
struct SWVoiceOut {
|
struct SWVoiceOut {
|
||||||
QEMUSoundCard *card;
|
QEMUSoundCard *card;
|
||||||
|
AudioState *s;
|
||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
t_sample *conv;
|
t_sample *conv;
|
||||||
int64_t ratio;
|
int64_t ratio;
|
||||||
struct st_sample *buf;
|
struct st_sample *buf;
|
||||||
void *rate;
|
void *rate;
|
||||||
int total_hw_samples_mixed;
|
size_t total_hw_samples_mixed;
|
||||||
int active;
|
int active;
|
||||||
int empty;
|
int empty;
|
||||||
HWVoiceOut *hw;
|
HWVoiceOut *hw;
|
||||||
@ -111,11 +115,12 @@ struct SWVoiceOut {
|
|||||||
|
|
||||||
struct SWVoiceIn {
|
struct SWVoiceIn {
|
||||||
QEMUSoundCard *card;
|
QEMUSoundCard *card;
|
||||||
|
AudioState *s;
|
||||||
int active;
|
int active;
|
||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
int64_t ratio;
|
int64_t ratio;
|
||||||
void *rate;
|
void *rate;
|
||||||
int total_hw_samples_acquired;
|
size_t total_hw_samples_acquired;
|
||||||
struct st_sample *buf;
|
struct st_sample *buf;
|
||||||
f_sample *clip;
|
f_sample *clip;
|
||||||
HWVoiceIn *hw;
|
HWVoiceIn *hw;
|
||||||
@ -144,14 +149,12 @@ struct audio_driver {
|
|||||||
struct audio_pcm_ops {
|
struct audio_pcm_ops {
|
||||||
int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
|
int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
|
||||||
void (*fini_out)(HWVoiceOut *hw);
|
void (*fini_out)(HWVoiceOut *hw);
|
||||||
int (*run_out) (HWVoiceOut *hw, int live);
|
size_t (*run_out)(HWVoiceOut *hw, size_t live);
|
||||||
int (*write) (SWVoiceOut *sw, void *buf, int size);
|
|
||||||
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
|
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
|
||||||
|
|
||||||
int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
|
int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
|
||||||
void (*fini_in) (HWVoiceIn *hw);
|
void (*fini_in) (HWVoiceIn *hw);
|
||||||
int (*run_in) (HWVoiceIn *hw);
|
size_t (*run_in)(HWVoiceIn *hw);
|
||||||
int (*read) (SWVoiceIn *sw, void *buf, int size);
|
|
||||||
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
|
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -188,6 +191,11 @@ typedef struct AudioState {
|
|||||||
int nb_hw_voices_in;
|
int nb_hw_voices_in;
|
||||||
int vm_running;
|
int vm_running;
|
||||||
int64_t period_ticks;
|
int64_t period_ticks;
|
||||||
|
|
||||||
|
bool timer_running;
|
||||||
|
uint64_t timer_last;
|
||||||
|
|
||||||
|
QTAILQ_ENTRY(AudioState) list;
|
||||||
} AudioState;
|
} AudioState;
|
||||||
|
|
||||||
extern const struct mixeng_volume nominal_volume;
|
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_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);
|
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);
|
size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw);
|
||||||
int audio_pcm_hw_get_live_in (HWVoiceIn *hw);
|
|
||||||
|
|
||||||
int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
|
size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
|
||||||
|
size_t live, size_t pending);
|
||||||
int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
|
|
||||||
int live, int pending);
|
|
||||||
|
|
||||||
int audio_bug (const char *funcname, int cond);
|
int audio_bug (const char *funcname, int cond);
|
||||||
void *audio_calloc (const char *funcname, int nmemb, size_t size);
|
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_ENABLE 1
|
||||||
#define VOICE_DISABLE 2
|
#define VOICE_DISABLE 2
|
||||||
@ -219,7 +224,7 @@ void audio_run (const char *msg);
|
|||||||
|
|
||||||
#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
|
#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);
|
return (dst >= src) ? (dst - src) : (len - src + dst);
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,9 @@
|
|||||||
#define HWBUF hw->conv_buf
|
#define HWBUF hw->conv_buf
|
||||||
#endif
|
#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 max_voices = glue (drv->max_voices_, TYPE);
|
||||||
int voice_size = glue (drv->voice_size_, 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;
|
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));
|
HWBUF = audio_calloc(__func__, hw->samples, sizeof(struct st_sample));
|
||||||
if (!HWBUF) {
|
if (!HWBUF) {
|
||||||
dolog ("Could not allocate " NAME " buffer (%d samples)\n",
|
dolog("Could not allocate " NAME " buffer (%zu samples)\n",
|
||||||
hw->samples);
|
hw->samples);
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
|
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)
|
static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
|
||||||
{
|
{
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
HW *hw = *hwp;
|
HW *hw = *hwp;
|
||||||
|
AudioState *s = hw->s;
|
||||||
|
|
||||||
if (!hw->sw_head.lh_first) {
|
if (!hw->sw_head.lh_first) {
|
||||||
#ifdef DAC
|
#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;
|
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) {
|
if (hw->enabled) {
|
||||||
return hw;
|
return hw;
|
||||||
}
|
}
|
||||||
@ -215,12 +214,10 @@ static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
static HW *glue(audio_pcm_hw_find_specific_, TYPE)(AudioState *s, HW *hw,
|
||||||
HW *hw,
|
struct audsettings *as)
|
||||||
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)) {
|
if (audio_pcm_info_eq (&hw->info, as)) {
|
||||||
return hw;
|
return hw;
|
||||||
}
|
}
|
||||||
@ -228,10 +225,10 @@ static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
|||||||
return NULL;
|
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;
|
HW *hw;
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
struct audio_driver *drv = s->drv;
|
struct audio_driver *drv = s->drv;
|
||||||
|
|
||||||
if (!glue (s->nb_hw_voices_, TYPE)) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hw->s = s;
|
||||||
hw->pcm_ops = drv->pcm_ops;
|
hw->pcm_ops = drv->pcm_ops;
|
||||||
hw->ctl_caps = drv->ctl_caps;
|
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)) {
|
if (audio_bug(__func__, hw->samples <= 0)) {
|
||||||
dolog ("hw->samples=%d\n", hw->samples);
|
dolog("hw->samples=%zd\n", hw->samples);
|
||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +279,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
|
|||||||
[hw->info.swap_endianness]
|
[hw->info.swap_endianness]
|
||||||
[audio_bits_to_index (hw->info.bits)];
|
[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;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,33 +326,33 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
|||||||
abort();
|
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;
|
HW *hw;
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
||||||
|
|
||||||
if (pdo->fixed_settings) {
|
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) {
|
if (hw) {
|
||||||
return 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) {
|
if (hw) {
|
||||||
return hw;
|
return hw;
|
||||||
}
|
}
|
||||||
|
|
||||||
hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
|
hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
|
||||||
if (hw) {
|
if (hw) {
|
||||||
return 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,
|
const char *sw_name,
|
||||||
struct audsettings *as
|
struct audsettings *as
|
||||||
)
|
)
|
||||||
@ -362,7 +360,6 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
|||||||
SW *sw;
|
SW *sw;
|
||||||
HW *hw;
|
HW *hw;
|
||||||
struct audsettings hw_as;
|
struct audsettings hw_as;
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
||||||
|
|
||||||
if (pdo->fixed_settings) {
|
if (pdo->fixed_settings) {
|
||||||
@ -378,8 +375,9 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
|||||||
sw_name ? sw_name : "unknown", sizeof (*sw));
|
sw_name ? sw_name : "unknown", sizeof (*sw));
|
||||||
goto err1;
|
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) {
|
if (!hw) {
|
||||||
goto err2;
|
goto err2;
|
||||||
}
|
}
|
||||||
@ -430,7 +428,7 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
struct audsettings *as
|
struct audsettings *as
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
AudioState *s = &glob_audio_state;
|
AudioState *s = card->state;
|
||||||
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
|
||||||
|
|
||||||
if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
|
if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
|
||||||
@ -476,7 +474,7 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as);
|
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
dolog ("Failed to create voice `%s'\n", name);
|
dolog ("Failed to create voice `%s'\n", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -43,9 +43,9 @@ typedef struct coreaudioVoiceOut {
|
|||||||
UInt32 audioDevicePropertyBufferFrameSize;
|
UInt32 audioDevicePropertyBufferFrameSize;
|
||||||
AudioStreamBasicDescription outputStreamBasicDescription;
|
AudioStreamBasicDescription outputStreamBasicDescription;
|
||||||
AudioDeviceIOProcID ioprocid;
|
AudioDeviceIOProcID ioprocid;
|
||||||
int live;
|
size_t live;
|
||||||
int decr;
|
size_t decr;
|
||||||
int rpos;
|
size_t rpos;
|
||||||
} coreaudioVoiceOut;
|
} coreaudioVoiceOut;
|
||||||
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
#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;
|
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;
|
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||||
|
|
||||||
if (coreaudio_lock (core, "coreaudio_run_out")) {
|
if (coreaudio_lock (core, "coreaudio_run_out")) {
|
||||||
@ -413,7 +413,7 @@ static int coreaudio_run_out (HWVoiceOut *hw, int live)
|
|||||||
core->live);
|
core->live);
|
||||||
}
|
}
|
||||||
|
|
||||||
decr = audio_MIN (core->decr, live);
|
decr = MIN (core->decr, live);
|
||||||
core->decr -= decr;
|
core->decr -= decr;
|
||||||
|
|
||||||
core->live = live - decr;
|
core->live = live - decr;
|
||||||
@ -489,11 +489,6 @@ static OSStatus audioDeviceIOProc(
|
|||||||
return 0;
|
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,
|
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||||
void *drv_opaque)
|
void *drv_opaque)
|
||||||
{
|
{
|
||||||
@ -692,7 +687,6 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
|
|||||||
.init_out = coreaudio_init_out,
|
.init_out = coreaudio_init_out,
|
||||||
.fini_out = coreaudio_fini_out,
|
.fini_out = coreaudio_fini_out,
|
||||||
.run_out = coreaudio_run_out,
|
.run_out = coreaudio_run_out,
|
||||||
.write = coreaudio_write,
|
|
||||||
.ctl_out = coreaudio_ctl_out
|
.ctl_out = coreaudio_ctl_out
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -454,24 +454,20 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsound_write (SWVoiceOut *sw, void *buf, int len)
|
static size_t dsound_run_out(HWVoiceOut *hw, size_t live)
|
||||||
{
|
|
||||||
return audio_pcm_sw_write (sw, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dsound_run_out (HWVoiceOut *hw, int live)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
||||||
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
||||||
int len, hwshift;
|
size_t len;
|
||||||
|
int hwshift;
|
||||||
DWORD blen1, blen2;
|
DWORD blen1, blen2;
|
||||||
DWORD len1, len2;
|
DWORD len1, len2;
|
||||||
DWORD decr;
|
DWORD decr;
|
||||||
DWORD wpos, ppos, old_pos;
|
DWORD wpos, ppos, old_pos;
|
||||||
LPVOID p1, p2;
|
LPVOID p1, p2;
|
||||||
int bufsize;
|
size_t bufsize;
|
||||||
dsound *s = ds->s;
|
dsound *s = ds->s;
|
||||||
AudiodevDsoundOptions *dso = &s->dev->u.dsound;
|
AudiodevDsoundOptions *dso = &s->dev->u.dsound;
|
||||||
|
|
||||||
@ -538,8 +534,8 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, len < 0 || len > bufsize)) {
|
if (audio_bug(__func__, len > bufsize)) {
|
||||||
dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
|
dolog("len=%zu bufsize=%zu old_pos=%ld ppos=%ld\n",
|
||||||
len, bufsize, old_pos, ppos);
|
len, bufsize, old_pos, ppos);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -645,18 +641,13 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsound_read (SWVoiceIn *sw, void *buf, int len)
|
static size_t dsound_run_in(HWVoiceIn *hw)
|
||||||
{
|
|
||||||
return audio_pcm_sw_read (sw, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dsound_run_in (HWVoiceIn *hw)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||||
int live, len, dead;
|
size_t live, len, dead;
|
||||||
DWORD blen1, blen2;
|
DWORD blen1, blen2;
|
||||||
DWORD len1, len2;
|
DWORD len1, len2;
|
||||||
DWORD decr;
|
DWORD decr;
|
||||||
@ -707,7 +698,7 @@ static int dsound_run_in (HWVoiceIn *hw)
|
|||||||
if (!len) {
|
if (!len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
len = audio_MIN (len, dead);
|
len = MIN (len, dead);
|
||||||
|
|
||||||
err = dsound_lock_in (
|
err = dsound_lock_in (
|
||||||
dscb,
|
dscb,
|
||||||
@ -856,13 +847,11 @@ static struct audio_pcm_ops dsound_pcm_ops = {
|
|||||||
.init_out = dsound_init_out,
|
.init_out = dsound_init_out,
|
||||||
.fini_out = dsound_fini_out,
|
.fini_out = dsound_fini_out,
|
||||||
.run_out = dsound_run_out,
|
.run_out = dsound_run_out,
|
||||||
.write = dsound_write,
|
|
||||||
.ctl_out = dsound_ctl_out,
|
.ctl_out = dsound_ctl_out,
|
||||||
|
|
||||||
.init_in = dsound_init_in,
|
.init_in = dsound_init_in,
|
||||||
.fini_in = dsound_fini_in,
|
.fini_in = dsound_fini_in,
|
||||||
.run_in = dsound_run_in,
|
.run_in = dsound_run_in,
|
||||||
.read = dsound_read,
|
|
||||||
.ctl_in = dsound_ctl_in
|
.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 mixeng_volume { int mute; int64_t r; int64_t l; };
|
||||||
struct st_sample { int64_t l; int64_t r; };
|
struct st_sample { int64_t l; int64_t r; };
|
||||||
#endif
|
#endif
|
||||||
|
typedef struct st_sample st_sample;
|
||||||
|
|
||||||
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
|
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);
|
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];
|
extern f_sample *mixeng_clip[2][2][2][3];
|
||||||
|
|
||||||
void *st_rate_start (int inrate, int outrate);
|
void *st_rate_start (int inrate, int outrate);
|
||||||
void st_rate_flow (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||||
int *isamp, int *osamp);
|
size_t *isamp, size_t *osamp);
|
||||||
void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||||
int *isamp, int *osamp);
|
size_t *isamp, size_t *osamp);
|
||||||
void st_rate_stop (void *opaque);
|
void st_rate_stop (void *opaque);
|
||||||
void mixeng_clear (struct st_sample *buf, int len);
|
void mixeng_clear (struct st_sample *buf, int len);
|
||||||
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
||||||
|
@ -41,10 +41,10 @@ typedef struct NoVoiceIn {
|
|||||||
int64_t old_ticks;
|
int64_t old_ticks;
|
||||||
} NoVoiceIn;
|
} 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;
|
NoVoiceOut *no = (NoVoiceOut *) hw;
|
||||||
int decr, samples;
|
size_t decr, samples;
|
||||||
int64_t now;
|
int64_t now;
|
||||||
int64_t ticks;
|
int64_t ticks;
|
||||||
int64_t bytes;
|
int64_t bytes;
|
||||||
@ -52,20 +52,15 @@ static int no_run_out (HWVoiceOut *hw, int live)
|
|||||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
ticks = now - no->old_ticks;
|
ticks = now - no->old_ticks;
|
||||||
bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
|
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;
|
samples = bytes >> hw->info.shift;
|
||||||
|
|
||||||
no->old_ticks = now;
|
no->old_ticks = now;
|
||||||
decr = audio_MIN (live, samples);
|
decr = MIN (live, samples);
|
||||||
hw->rpos = (hw->rpos + decr) % hw->samples;
|
hw->rpos = (hw->rpos + decr) % hw->samples;
|
||||||
return decr;
|
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)
|
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
||||||
{
|
{
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
@ -97,12 +92,12 @@ static void no_fini_in (HWVoiceIn *hw)
|
|||||||
(void) hw;
|
(void) hw;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int no_run_in (HWVoiceIn *hw)
|
static size_t no_run_in(HWVoiceIn *hw)
|
||||||
{
|
{
|
||||||
NoVoiceIn *no = (NoVoiceIn *) hw;
|
NoVoiceIn *no = (NoVoiceIn *) hw;
|
||||||
int live = audio_pcm_hw_get_live_in (hw);
|
size_t live = audio_pcm_hw_get_live_in(hw);
|
||||||
int dead = hw->samples - live;
|
size_t dead = hw->samples - live;
|
||||||
int samples = 0;
|
size_t samples = 0;
|
||||||
|
|
||||||
if (dead) {
|
if (dead) {
|
||||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
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);
|
muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
|
||||||
|
|
||||||
no->old_ticks = now;
|
no->old_ticks = now;
|
||||||
bytes = audio_MIN (bytes, INT_MAX);
|
bytes = MIN (bytes, SIZE_MAX);
|
||||||
samples = bytes >> hw->info.shift;
|
samples = bytes >> hw->info.shift;
|
||||||
samples = audio_MIN (samples, dead);
|
samples = MIN (samples, dead);
|
||||||
}
|
}
|
||||||
return samples;
|
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, ...)
|
static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||||
{
|
{
|
||||||
(void) hw;
|
(void) hw;
|
||||||
@ -151,13 +134,11 @@ static struct audio_pcm_ops no_pcm_ops = {
|
|||||||
.init_out = no_init_out,
|
.init_out = no_init_out,
|
||||||
.fini_out = no_fini_out,
|
.fini_out = no_fini_out,
|
||||||
.run_out = no_run_out,
|
.run_out = no_run_out,
|
||||||
.write = no_write,
|
|
||||||
.ctl_out = no_ctl_out,
|
.ctl_out = no_ctl_out,
|
||||||
|
|
||||||
.init_in = no_init_in,
|
.init_in = no_init_in,
|
||||||
.fini_in = no_fini_in,
|
.fini_in = no_fini_in,
|
||||||
.run_in = no_run_in,
|
.run_in = no_run_in,
|
||||||
.read = no_read,
|
|
||||||
.ctl_in = no_ctl_in
|
.ctl_in = no_ctl_in
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,33 +110,28 @@ static void oss_anal_close (int *fdp)
|
|||||||
|
|
||||||
static void oss_helper_poll_out (void *opaque)
|
static void oss_helper_poll_out (void *opaque)
|
||||||
{
|
{
|
||||||
(void) opaque;
|
AudioState *s = opaque;
|
||||||
audio_run ("oss_poll_out");
|
audio_run(s, "oss_poll_out");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void oss_helper_poll_in (void *opaque)
|
static void oss_helper_poll_in (void *opaque)
|
||||||
{
|
{
|
||||||
(void) opaque;
|
AudioState *s = opaque;
|
||||||
audio_run ("oss_poll_in");
|
audio_run(s, "oss_poll_in");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void oss_poll_out (HWVoiceOut *hw)
|
static void oss_poll_out (HWVoiceOut *hw)
|
||||||
{
|
{
|
||||||
OSSVoiceOut *oss = (OSSVoiceOut *) 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)
|
static void oss_poll_in (HWVoiceIn *hw)
|
||||||
{
|
{
|
||||||
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
||||||
|
|
||||||
qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
|
qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s);
|
||||||
}
|
|
||||||
|
|
||||||
static int oss_write (SWVoiceOut *sw, void *buf, int len)
|
|
||||||
{
|
|
||||||
return audio_pcm_sw_write (sw, buf, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aud_to_ossfmt (AudioFormat fmt, int endianness)
|
static int aud_to_ossfmt (AudioFormat fmt, int endianness)
|
||||||
@ -388,7 +383,7 @@ static void oss_write_pending (OSSVoiceOut *oss)
|
|||||||
int samples_written;
|
int samples_written;
|
||||||
ssize_t bytes_written;
|
ssize_t bytes_written;
|
||||||
int samples_till_end = hw->samples - oss->wpos;
|
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;
|
int bytes_to_write = samples_to_write << hw->info.shift;
|
||||||
void *pcm = advance (oss->pcm_buf, oss->wpos << 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;
|
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||||
int err, decr;
|
int err;
|
||||||
|
size_t decr;
|
||||||
struct audio_buf_info abinfo;
|
struct audio_buf_info abinfo;
|
||||||
struct count_info cntinfo;
|
struct count_info cntinfo;
|
||||||
int bufsize;
|
size_t bufsize;
|
||||||
|
|
||||||
bufsize = hw->samples << hw->info.shift;
|
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;
|
pos = hw->rpos << hw->info.shift;
|
||||||
bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
|
bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
|
||||||
decr = audio_MIN (bytes >> hw->info.shift, live);
|
decr = MIN (bytes >> hw->info.shift, live);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
|
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
|
||||||
@ -456,7 +452,7 @@ static int oss_run_out (HWVoiceOut *hw, int live)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
|
decr = MIN (abinfo.bytes >> hw->info.shift, live);
|
||||||
if (!decr) {
|
if (!decr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -481,7 +477,7 @@ static void oss_fini_out (HWVoiceOut *hw)
|
|||||||
if (oss->mmapped) {
|
if (oss->mmapped) {
|
||||||
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
|
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
|
||||||
if (err) {
|
if (err) {
|
||||||
oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
|
oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n",
|
||||||
oss->pcm_buf, hw->samples << hw->info.shift);
|
oss->pcm_buf, hw->samples << hw->info.shift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,7 +544,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
if (oss->pcm_buf == MAP_FAILED) {
|
if (oss->pcm_buf == MAP_FAILED) {
|
||||||
oss_logerr (errno, "Failed to map %d bytes of DAC\n",
|
oss_logerr(errno, "Failed to map %zu bytes of DAC\n",
|
||||||
hw->samples << hw->info.shift);
|
hw->samples << hw->info.shift);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -573,7 +569,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
if (!oss->mmapped) {
|
if (!oss->mmapped) {
|
||||||
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
|
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
|
||||||
if (err) {
|
if (err) {
|
||||||
oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
|
oss_logerr(errno, "Failed to unmap buffer %p size %zu\n",
|
||||||
oss->pcm_buf, hw->samples << hw->info.shift);
|
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);
|
1 << hw->info.shift);
|
||||||
if (!oss->pcm_buf) {
|
if (!oss->pcm_buf) {
|
||||||
dolog (
|
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,
|
hw->samples,
|
||||||
1 << hw->info.shift
|
1 << hw->info.shift
|
||||||
);
|
);
|
||||||
@ -698,7 +694,7 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
|||||||
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
|
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
|
||||||
oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||||
if (!oss->pcm_buf) {
|
if (!oss->pcm_buf) {
|
||||||
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
|
dolog("Could not allocate ADC buffer (%zu samples, each %d bytes)\n",
|
||||||
hw->samples, 1 << hw->info.shift);
|
hw->samples, 1 << hw->info.shift);
|
||||||
oss_anal_close (&fd);
|
oss_anal_close (&fd);
|
||||||
return -1;
|
return -1;
|
||||||
@ -719,17 +715,17 @@ static void oss_fini_in (HWVoiceIn *hw)
|
|||||||
oss->pcm_buf = NULL;
|
oss->pcm_buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_run_in (HWVoiceIn *hw)
|
static size_t oss_run_in(HWVoiceIn *hw)
|
||||||
{
|
{
|
||||||
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
||||||
int hwshift = hw->info.shift;
|
int hwshift = hw->info.shift;
|
||||||
int i;
|
int i;
|
||||||
int live = audio_pcm_hw_get_live_in (hw);
|
size_t live = audio_pcm_hw_get_live_in (hw);
|
||||||
int dead = hw->samples - live;
|
size_t dead = hw->samples - live;
|
||||||
size_t read_samples = 0;
|
size_t read_samples = 0;
|
||||||
struct {
|
struct {
|
||||||
int add;
|
size_t add;
|
||||||
int len;
|
size_t len;
|
||||||
} bufs[2] = {
|
} bufs[2] = {
|
||||||
{ .add = hw->wpos, .len = 0 },
|
{ .add = hw->wpos, .len = 0 },
|
||||||
{ .add = 0, .len = 0 }
|
{ .add = 0, .len = 0 }
|
||||||
@ -756,7 +752,7 @@ static int oss_run_in (HWVoiceIn *hw)
|
|||||||
|
|
||||||
if (nread > 0) {
|
if (nread > 0) {
|
||||||
if (nread & hw->info.align) {
|
if (nread & hw->info.align) {
|
||||||
dolog ("warning: Misaligned read %zd (requested %d), "
|
dolog("warning: Misaligned read %zd (requested %zu), "
|
||||||
"alignment %d\n", nread, bufs[i].add << hwshift,
|
"alignment %d\n", nread, bufs[i].add << hwshift,
|
||||||
hw->info.align + 1);
|
hw->info.align + 1);
|
||||||
}
|
}
|
||||||
@ -771,9 +767,9 @@ static int oss_run_in (HWVoiceIn *hw)
|
|||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
oss_logerr (
|
oss_logerr(
|
||||||
errno,
|
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
|
bufs[i].len, p
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -788,11 +784,6 @@ static int oss_run_in (HWVoiceIn *hw)
|
|||||||
return read_samples;
|
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, ...)
|
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
||||||
{
|
{
|
||||||
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
||||||
@ -855,13 +846,11 @@ static struct audio_pcm_ops oss_pcm_ops = {
|
|||||||
.init_out = oss_init_out,
|
.init_out = oss_init_out,
|
||||||
.fini_out = oss_fini_out,
|
.fini_out = oss_fini_out,
|
||||||
.run_out = oss_run_out,
|
.run_out = oss_run_out,
|
||||||
.write = oss_write,
|
|
||||||
.ctl_out = oss_ctl_out,
|
.ctl_out = oss_ctl_out,
|
||||||
|
|
||||||
.init_in = oss_init_in,
|
.init_in = oss_init_in,
|
||||||
.fini_in = oss_fini_in,
|
.fini_in = oss_fini_in,
|
||||||
.run_in = oss_run_in,
|
.run_in = oss_run_in,
|
||||||
.read = oss_read,
|
|
||||||
.ctl_in = oss_ctl_in
|
.ctl_in = oss_ctl_in
|
||||||
};
|
};
|
||||||
|
|
||||||
|
411
audio/paaudio.c
411
audio/paaudio.c
@ -11,41 +11,52 @@
|
|||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
#include "audio_pt_int.h"
|
#include "audio_pt_int.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct PAConnection {
|
||||||
Audiodev *dev;
|
char *server;
|
||||||
|
int refcount;
|
||||||
|
QTAILQ_ENTRY(PAConnection) list;
|
||||||
|
|
||||||
pa_threaded_mainloop *mainloop;
|
pa_threaded_mainloop *mainloop;
|
||||||
pa_context *context;
|
pa_context *context;
|
||||||
|
} PAConnection;
|
||||||
|
|
||||||
|
static QTAILQ_HEAD(PAConnectionHead, PAConnection) pa_conns =
|
||||||
|
QTAILQ_HEAD_INITIALIZER(pa_conns);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Audiodev *dev;
|
||||||
|
PAConnection *conn;
|
||||||
} paaudio;
|
} paaudio;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
int done;
|
size_t done;
|
||||||
int live;
|
size_t live;
|
||||||
int decr;
|
size_t decr;
|
||||||
int rpos;
|
size_t rpos;
|
||||||
pa_stream *stream;
|
pa_stream *stream;
|
||||||
void *pcm_buf;
|
void *pcm_buf;
|
||||||
struct audio_pt pt;
|
struct audio_pt pt;
|
||||||
paaudio *g;
|
paaudio *g;
|
||||||
int samples;
|
size_t samples;
|
||||||
} PAVoiceOut;
|
} PAVoiceOut;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HWVoiceIn hw;
|
HWVoiceIn hw;
|
||||||
int done;
|
size_t done;
|
||||||
int dead;
|
size_t dead;
|
||||||
int incr;
|
size_t incr;
|
||||||
int wpos;
|
size_t wpos;
|
||||||
pa_stream *stream;
|
pa_stream *stream;
|
||||||
void *pcm_buf;
|
void *pcm_buf;
|
||||||
struct audio_pt pt;
|
struct audio_pt pt;
|
||||||
const void *read_data;
|
const void *read_data;
|
||||||
size_t read_index, read_length;
|
size_t read_index, read_length;
|
||||||
paaudio *g;
|
paaudio *g;
|
||||||
int samples;
|
size_t samples;
|
||||||
} PAVoiceIn;
|
} 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, ...)
|
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)
|
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) {
|
while (length > 0) {
|
||||||
size_t l;
|
size_t l;
|
||||||
@ -121,11 +132,11 @@ static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
|
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) {
|
if (!p->read_data) {
|
||||||
pa_threaded_mainloop_wait (g->mainloop);
|
pa_threaded_mainloop_wait(c->mainloop);
|
||||||
CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
|
CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
|
||||||
} else {
|
} else {
|
||||||
p->read_index = 0;
|
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_length = 0;
|
||||||
p->read_index = 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;
|
return 0;
|
||||||
|
|
||||||
unlock_and_fail:
|
unlock_and_fail:
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
pa_threaded_mainloop_unlock(c->mainloop);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
|
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) {
|
while (length > 0) {
|
||||||
size_t l;
|
size_t l;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
while (!(l = pa_stream_writable_size (p->stream))) {
|
while (!(l = pa_stream_writable_size (p->stream))) {
|
||||||
pa_threaded_mainloop_wait (g->mainloop);
|
pa_threaded_mainloop_wait(c->mainloop);
|
||||||
CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
|
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) {
|
if (l > length) {
|
||||||
l = length;
|
l = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
|
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;
|
data = (const uint8_t *) data + l;
|
||||||
length -= l;
|
length -= l;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
pa_threaded_mainloop_unlock(c->mainloop);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unlock_and_fail:
|
unlock_and_fail:
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
pa_threaded_mainloop_unlock(c->mainloop);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +219,7 @@ static void *qpa_thread_out (void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int decr, to_mix, rpos;
|
size_t decr, to_mix, rpos;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (pa->done) {
|
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;
|
rpos = pa->rpos;
|
||||||
|
|
||||||
if (audio_pt_unlock(&pa->pt, __func__)) {
|
if (audio_pt_unlock(&pa->pt, __func__)) {
|
||||||
@ -233,7 +244,7 @@ static void *qpa_thread_out (void *arg)
|
|||||||
|
|
||||||
while (to_mix) {
|
while (to_mix) {
|
||||||
int error;
|
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;
|
struct st_sample *src = hw->mix_buf + rpos;
|
||||||
|
|
||||||
hw->clip (pa->pcm_buf, src, chunk);
|
hw->clip (pa->pcm_buf, src, chunk);
|
||||||
@ -262,16 +273,16 @@ static void *qpa_thread_out (void *arg)
|
|||||||
return NULL;
|
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;
|
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||||
|
|
||||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
if (audio_pt_lock(&pa->pt, __func__)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
decr = audio_MIN (live, pa->decr);
|
decr = MIN (live, pa->decr);
|
||||||
pa->decr -= decr;
|
pa->decr -= decr;
|
||||||
pa->live = live - decr;
|
pa->live = live - decr;
|
||||||
hw->rpos = pa->rpos;
|
hw->rpos = pa->rpos;
|
||||||
@ -284,11 +295,6 @@ static int qpa_run_out (HWVoiceOut *hw, int live)
|
|||||||
return decr;
|
return decr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qpa_write (SWVoiceOut *sw, void *buf, int len)
|
|
||||||
{
|
|
||||||
return audio_pcm_sw_write (sw, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* capture */
|
/* capture */
|
||||||
static void *qpa_thread_in (void *arg)
|
static void *qpa_thread_in (void *arg)
|
||||||
{
|
{
|
||||||
@ -300,7 +306,7 @@ static void *qpa_thread_in (void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int incr, to_grab, wpos;
|
size_t incr, to_grab, wpos;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (pa->done) {
|
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;
|
wpos = pa->wpos;
|
||||||
|
|
||||||
if (audio_pt_unlock(&pa->pt, __func__)) {
|
if (audio_pt_unlock(&pa->pt, __func__)) {
|
||||||
@ -325,7 +331,7 @@ static void *qpa_thread_in (void *arg)
|
|||||||
|
|
||||||
while (to_grab) {
|
while (to_grab) {
|
||||||
int error;
|
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);
|
void *buf = advance (pa->pcm_buf, wpos);
|
||||||
|
|
||||||
if (qpa_simple_read (pa, buf,
|
if (qpa_simple_read (pa, buf,
|
||||||
@ -353,9 +359,9 @@ static void *qpa_thread_in (void *arg)
|
|||||||
return NULL;
|
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;
|
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||||
|
|
||||||
if (audio_pt_lock(&pa->pt, __func__)) {
|
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);
|
live = audio_pcm_hw_get_live_in (hw);
|
||||||
dead = hw->samples - live;
|
dead = hw->samples - live;
|
||||||
incr = audio_MIN (dead, pa->incr);
|
incr = MIN (dead, pa->incr);
|
||||||
pa->incr -= incr;
|
pa->incr -= incr;
|
||||||
pa->dead = dead - incr;
|
pa->dead = dead - incr;
|
||||||
hw->wpos = pa->wpos;
|
hw->wpos = pa->wpos;
|
||||||
@ -377,11 +383,6 @@ static int qpa_run_in (HWVoiceIn *hw)
|
|||||||
return incr;
|
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)
|
static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
|
||||||
{
|
{
|
||||||
int format;
|
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)
|
static void context_state_cb (pa_context *c, void *userdata)
|
||||||
{
|
{
|
||||||
paaudio *g = userdata;
|
PAConnection *conn = userdata;
|
||||||
|
|
||||||
switch (pa_context_get_state(c)) {
|
switch (pa_context_get_state(c)) {
|
||||||
case PA_CONTEXT_READY:
|
case PA_CONTEXT_READY:
|
||||||
case PA_CONTEXT_TERMINATED:
|
case PA_CONTEXT_TERMINATED:
|
||||||
case PA_CONTEXT_FAILED:
|
case PA_CONTEXT_FAILED:
|
||||||
pa_threaded_mainloop_signal (g->mainloop, 0);
|
pa_threaded_mainloop_signal(conn->mainloop, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PA_CONTEXT_UNCONNECTED:
|
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)
|
static void stream_state_cb (pa_stream *s, void * userdata)
|
||||||
{
|
{
|
||||||
paaudio *g = userdata;
|
PAConnection *c = userdata;
|
||||||
|
|
||||||
switch (pa_stream_get_state (s)) {
|
switch (pa_stream_get_state (s)) {
|
||||||
|
|
||||||
case PA_STREAM_READY:
|
case PA_STREAM_READY:
|
||||||
case PA_STREAM_FAILED:
|
case PA_STREAM_FAILED:
|
||||||
case PA_STREAM_TERMINATED:
|
case PA_STREAM_TERMINATED:
|
||||||
pa_threaded_mainloop_signal (g->mainloop, 0);
|
pa_threaded_mainloop_signal(c->mainloop, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PA_STREAM_UNCONNECTED:
|
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)
|
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 (
|
static pa_stream *qpa_simple_new (
|
||||||
paaudio *g,
|
PAConnection *c,
|
||||||
const char *name,
|
const char *name,
|
||||||
pa_stream_direction_t dir,
|
pa_stream_direction_t dir,
|
||||||
const char *dev,
|
const char *dev,
|
||||||
@ -486,50 +487,51 @@ static pa_stream *qpa_simple_new (
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
pa_stream *stream;
|
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) {
|
if (!stream) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_stream_set_state_callback (stream, stream_state_cb, g);
|
pa_stream_set_state_callback(stream, stream_state_cb, c);
|
||||||
pa_stream_set_read_callback (stream, stream_request_cb, g);
|
pa_stream_set_read_callback(stream, stream_request_cb, c);
|
||||||
pa_stream_set_write_callback (stream, stream_request_cb, g);
|
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) {
|
if (dir == PA_STREAM_PLAYBACK) {
|
||||||
r = pa_stream_connect_playback (stream, dev, attr,
|
r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL);
|
||||||
PA_STREAM_INTERPOLATE_TIMING
|
|
||||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
|
||||||
|PA_STREAM_ADJUST_LATENCY
|
|
||||||
#endif
|
|
||||||
|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
r = pa_stream_connect_record (stream, dev, attr,
|
r = pa_stream_connect_record(stream, dev, attr, flags);
|
||||||
PA_STREAM_INTERPOLATE_TIMING
|
|
||||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
|
||||||
|PA_STREAM_ADJUST_LATENCY
|
|
||||||
#endif
|
|
||||||
|PA_STREAM_AUTO_TIMING_UPDATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
pa_threaded_mainloop_unlock(c->mainloop);
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
pa_threaded_mainloop_unlock(c->mainloop);
|
||||||
|
|
||||||
if (stream) {
|
if (stream) {
|
||||||
pa_stream_unref (stream);
|
pa_stream_unref (stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
*rerror = pa_context_errno (g->context);
|
*rerror = pa_context_errno(c->context);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -545,6 +547,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
paaudio *g = pa->g = drv_opaque;
|
paaudio *g = pa->g = drv_opaque;
|
||||||
AudiodevPaOptions *popts = &g->dev->u.pa;
|
AudiodevPaOptions *popts = &g->dev->u.pa;
|
||||||
AudiodevPaPerDirectionOptions *ppdo = popts->out;
|
AudiodevPaPerDirectionOptions *ppdo = popts->out;
|
||||||
|
PAConnection *c = g->conn;
|
||||||
|
|
||||||
ss.format = audfmt_to_pa (as->fmt, as->endianness);
|
ss.format = audfmt_to_pa (as->fmt, as->endianness);
|
||||||
ss.channels = as->nchannels;
|
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);
|
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
|
||||||
|
|
||||||
pa->stream = qpa_simple_new (
|
pa->stream = qpa_simple_new (
|
||||||
g,
|
c,
|
||||||
"qemu",
|
"qemu",
|
||||||
PA_STREAM_PLAYBACK,
|
PA_STREAM_PLAYBACK,
|
||||||
ppdo->has_name ? ppdo->name : NULL,
|
ppdo->has_name ? ppdo->name : NULL,
|
||||||
@ -579,7 +582,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||||
pa->rpos = hw->rpos;
|
pa->rpos = hw->rpos;
|
||||||
if (!pa->pcm_buf) {
|
if (!pa->pcm_buf) {
|
||||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
dolog("Could not allocate buffer (%zu bytes)\n",
|
||||||
hw->samples << hw->info.shift);
|
hw->samples << hw->info.shift);
|
||||||
goto fail2;
|
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;
|
paaudio *g = pa->g = drv_opaque;
|
||||||
AudiodevPaOptions *popts = &g->dev->u.pa;
|
AudiodevPaOptions *popts = &g->dev->u.pa;
|
||||||
AudiodevPaPerDirectionOptions *ppdo = popts->in;
|
AudiodevPaPerDirectionOptions *ppdo = popts->in;
|
||||||
|
PAConnection *c = g->conn;
|
||||||
|
|
||||||
ss.format = audfmt_to_pa (as->fmt, as->endianness);
|
ss.format = audfmt_to_pa (as->fmt, as->endianness);
|
||||||
ss.channels = as->nchannels;
|
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);
|
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
|
||||||
|
|
||||||
pa->stream = qpa_simple_new (
|
pa->stream = qpa_simple_new (
|
||||||
g,
|
c,
|
||||||
"qemu",
|
"qemu",
|
||||||
PA_STREAM_RECORD,
|
PA_STREAM_RECORD,
|
||||||
ppdo->has_name ? ppdo->name : NULL,
|
ppdo->has_name ? ppdo->name : NULL,
|
||||||
@ -646,7 +650,7 @@ 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->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||||
pa->wpos = hw->wpos;
|
pa->wpos = hw->wpos;
|
||||||
if (!pa->pcm_buf) {
|
if (!pa->pcm_buf) {
|
||||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
dolog("Could not allocate buffer (%zu bytes)\n",
|
||||||
hw->samples << hw->info.shift);
|
hw->samples << hw->info.shift);
|
||||||
goto fail2;
|
goto fail2;
|
||||||
}
|
}
|
||||||
@ -669,6 +673,27 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
|||||||
return -1;
|
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)
|
static void qpa_fini_out (HWVoiceOut *hw)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
@ -680,7 +705,7 @@ static void qpa_fini_out (HWVoiceOut *hw)
|
|||||||
audio_pt_join(&pa->pt, &ret, __func__);
|
audio_pt_join(&pa->pt, &ret, __func__);
|
||||||
|
|
||||||
if (pa->stream) {
|
if (pa->stream) {
|
||||||
pa_stream_unref (pa->stream);
|
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||||
pa->stream = NULL;
|
pa->stream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,7 +725,7 @@ static void qpa_fini_in (HWVoiceIn *hw)
|
|||||||
audio_pt_join(&pa->pt, &ret, __func__);
|
audio_pt_join(&pa->pt, &ret, __func__);
|
||||||
|
|
||||||
if (pa->stream) {
|
if (pa->stream) {
|
||||||
pa_stream_unref (pa->stream);
|
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||||
pa->stream = NULL;
|
pa->stream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,7 +739,7 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
|||||||
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||||
pa_operation *op;
|
pa_operation *op;
|
||||||
pa_cvolume v;
|
pa_cvolume v;
|
||||||
paaudio *g = pa->g;
|
PAConnection *c = pa->g->conn;
|
||||||
|
|
||||||
#ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */
|
#ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */
|
||||||
pa_cvolume_init (&v); /* function is present in 0.9.13+ */
|
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[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;
|
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),
|
pa_stream_get_index (pa->stream),
|
||||||
&v, NULL, NULL);
|
&v, NULL, NULL);
|
||||||
if (!op)
|
if (!op) {
|
||||||
qpa_logerr (pa_context_errno (g->context),
|
qpa_logerr(pa_context_errno(c->context),
|
||||||
"set_sink_input_volume() failed\n");
|
"set_sink_input_volume() failed\n");
|
||||||
else
|
} else {
|
||||||
pa_operation_unref (op);
|
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),
|
pa_stream_get_index (pa->stream),
|
||||||
sw->vol.mute, NULL, NULL);
|
sw->vol.mute, NULL, NULL);
|
||||||
if (!op) {
|
if (!op) {
|
||||||
qpa_logerr (pa_context_errno (g->context),
|
qpa_logerr(pa_context_errno(c->context),
|
||||||
"set_sink_input_mute() failed\n");
|
"set_sink_input_mute() failed\n");
|
||||||
} else {
|
} else {
|
||||||
pa_operation_unref (op);
|
pa_operation_unref(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
pa_threaded_mainloop_unlock(c->mainloop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -766,7 +792,7 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
|||||||
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||||
pa_operation *op;
|
pa_operation *op;
|
||||||
pa_cvolume v;
|
pa_cvolume v;
|
||||||
paaudio *g = pa->g;
|
PAConnection *c = pa->g->conn;
|
||||||
|
|
||||||
#ifdef PA_CHECK_VERSION
|
#ifdef PA_CHECK_VERSION
|
||||||
pa_cvolume_init (&v);
|
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[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;
|
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,
|
op = pa_context_set_source_output_volume(c->context,
|
||||||
pa_stream_get_index (pa->stream),
|
pa_stream_get_index(pa->stream),
|
||||||
&v, NULL, NULL);
|
&v, NULL, NULL);
|
||||||
if (!op) {
|
if (!op) {
|
||||||
qpa_logerr (pa_context_errno (g->context),
|
qpa_logerr(pa_context_errno(c->context),
|
||||||
"set_source_output_volume() failed\n");
|
"set_source_output_volume() failed\n");
|
||||||
} else {
|
} else {
|
||||||
pa_operation_unref(op);
|
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),
|
pa_stream_get_index (pa->stream),
|
||||||
sw->vol.mute, NULL, NULL);
|
sw->vol.mute, NULL, NULL);
|
||||||
if (!op) {
|
if (!op) {
|
||||||
qpa_logerr (pa_context_errno (g->context),
|
qpa_logerr(pa_context_errno(c->context),
|
||||||
"set_source_output_mute() failed\n");
|
"set_source_output_mute() failed\n");
|
||||||
} else {
|
} else {
|
||||||
pa_operation_unref (op);
|
pa_operation_unref (op);
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
pa_threaded_mainloop_unlock(c->mainloop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -828,11 +854,75 @@ static int qpa_validate_per_direction_opts(Audiodev *dev,
|
|||||||
return 1;
|
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)
|
static void *qpa_audio_init(Audiodev *dev)
|
||||||
{
|
{
|
||||||
paaudio *g;
|
paaudio *g;
|
||||||
AudiodevPaOptions *popts = &dev->u.pa;
|
AudiodevPaOptions *popts = &dev->u.pa;
|
||||||
const char *server;
|
const char *server;
|
||||||
|
PAConnection *c;
|
||||||
|
|
||||||
|
assert(dev->driver == AUDIODEV_DRIVER_PA);
|
||||||
|
|
||||||
if (!popts->has_server) {
|
if (!popts->has_server) {
|
||||||
char pidfile[64];
|
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)) {
|
if (!qpa_validate_per_direction_opts(dev, popts->in)) {
|
||||||
goto fail;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!qpa_validate_per_direction_opts(dev, popts->out)) {
|
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->dev = dev;
|
||||||
g->mainloop = NULL;
|
|
||||||
g->context = NULL;
|
|
||||||
|
|
||||||
g->mainloop = pa_threaded_mainloop_new ();
|
QTAILQ_FOREACH(c, &pa_conns, list) {
|
||||||
if (!g->mainloop) {
|
if (server == NULL || c->server == NULL ?
|
||||||
goto fail;
|
server == c->server :
|
||||||
}
|
strcmp(server, c->server) == 0) {
|
||||||
|
g->conn = c;
|
||||||
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) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PA_CONTEXT_IS_GOOD (state)) {
|
|
||||||
qpa_logerr (pa_context_errno (g->context),
|
|
||||||
"Wrong context state\n");
|
|
||||||
goto unlock_and_fail;
|
|
||||||
}
|
}
|
||||||
|
if (!g->conn) {
|
||||||
/* Wait until the context is ready */
|
g->conn = qpa_conn_init(server);
|
||||||
pa_threaded_mainloop_wait (g->mainloop);
|
|
||||||
}
|
}
|
||||||
|
if (!g->conn) {
|
||||||
pa_threaded_mainloop_unlock (g->mainloop);
|
g_free(g);
|
||||||
|
|
||||||
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;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
++g->conn->refcount;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
static void qpa_audio_fini (void *opaque)
|
||||||
{
|
{
|
||||||
paaudio *g = opaque;
|
paaudio *g = opaque;
|
||||||
|
PAConnection *c = g->conn;
|
||||||
|
|
||||||
if (g->mainloop) {
|
if (--c->refcount == 0) {
|
||||||
pa_threaded_mainloop_stop (g->mainloop);
|
qpa_conn_fini(c);
|
||||||
}
|
|
||||||
|
|
||||||
if (g->context) {
|
|
||||||
pa_context_disconnect (g->context);
|
|
||||||
pa_context_unref (g->context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->mainloop) {
|
|
||||||
pa_threaded_mainloop_free (g->mainloop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(g);
|
g_free(g);
|
||||||
@ -945,13 +1006,11 @@ static struct audio_pcm_ops qpa_pcm_ops = {
|
|||||||
.init_out = qpa_init_out,
|
.init_out = qpa_init_out,
|
||||||
.fini_out = qpa_fini_out,
|
.fini_out = qpa_fini_out,
|
||||||
.run_out = qpa_run_out,
|
.run_out = qpa_run_out,
|
||||||
.write = qpa_write,
|
|
||||||
.ctl_out = qpa_ctl_out,
|
.ctl_out = qpa_ctl_out,
|
||||||
|
|
||||||
.init_in = qpa_init_in,
|
.init_in = qpa_init_in,
|
||||||
.fini_in = qpa_fini_in,
|
.fini_in = qpa_fini_in,
|
||||||
.run_in = qpa_run_in,
|
.run_in = qpa_run_in,
|
||||||
.read = qpa_read,
|
|
||||||
.ctl_in = qpa_ctl_in
|
.ctl_in = qpa_ctl_in
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
* Return number of samples processed.
|
* Return number of samples processed.
|
||||||
*/
|
*/
|
||||||
void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
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 rate *rate = opaque;
|
||||||
struct st_sample *istart, *iend;
|
struct st_sample *istart, *iend;
|
||||||
|
@ -41,8 +41,8 @@
|
|||||||
|
|
||||||
typedef struct SDLVoiceOut {
|
typedef struct SDLVoiceOut {
|
||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
int live;
|
size_t live;
|
||||||
int decr;
|
size_t decr;
|
||||||
} SDLVoiceOut;
|
} SDLVoiceOut;
|
||||||
|
|
||||||
static struct SDLAudioState {
|
static struct SDLAudioState {
|
||||||
@ -184,22 +184,22 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
|||||||
SDLVoiceOut *sdl = opaque;
|
SDLVoiceOut *sdl = opaque;
|
||||||
SDLAudioState *s = &glob_sdl;
|
SDLAudioState *s = &glob_sdl;
|
||||||
HWVoiceOut *hw = &sdl->hw;
|
HWVoiceOut *hw = &sdl->hw;
|
||||||
int samples = len >> hw->info.shift;
|
size_t samples = len >> hw->info.shift;
|
||||||
int to_mix, decr;
|
size_t to_mix, decr;
|
||||||
|
|
||||||
if (s->exit || !sdl->live) {
|
if (s->exit || !sdl->live) {
|
||||||
return;
|
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;
|
decr = to_mix;
|
||||||
while (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;
|
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->clip(buf, src, chunk);
|
||||||
hw->rpos = (hw->rpos + chunk) % hw->samples;
|
hw->rpos = (hw->rpos + chunk) % hw->samples;
|
||||||
to_mix -= chunk;
|
to_mix -= chunk;
|
||||||
@ -209,7 +209,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
|||||||
sdl->live -= decr;
|
sdl->live -= decr;
|
||||||
sdl->decr += 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 */
|
/* SDL2 does not clear the remaining buffer for us, so do it on our own */
|
||||||
if (samples) {
|
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);
|
size_t decr;
|
||||||
}
|
|
||||||
|
|
||||||
static int sdl_run_out (HWVoiceOut *hw, int live)
|
|
||||||
{
|
|
||||||
int decr;
|
|
||||||
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
||||||
|
|
||||||
SDL_LockAudio();
|
SDL_LockAudio();
|
||||||
@ -236,7 +231,7 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
|
|||||||
sdl->live);
|
sdl->live);
|
||||||
}
|
}
|
||||||
|
|
||||||
decr = audio_MIN (sdl->decr, live);
|
decr = MIN (sdl->decr, live);
|
||||||
sdl->decr -= decr;
|
sdl->decr -= decr;
|
||||||
|
|
||||||
sdl->live = live;
|
sdl->live = live;
|
||||||
@ -342,7 +337,6 @@ static struct audio_pcm_ops sdl_pcm_ops = {
|
|||||||
.init_out = sdl_init_out,
|
.init_out = sdl_init_out,
|
||||||
.fini_out = sdl_fini_out,
|
.fini_out = sdl_fini_out,
|
||||||
.run_out = sdl_run_out,
|
.run_out = sdl_run_out,
|
||||||
.write = sdl_write_out,
|
|
||||||
.ctl_out = sdl_ctl_out,
|
.ctl_out = sdl_ctl_out,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,31 +152,31 @@ static void line_out_fini (HWVoiceOut *hw)
|
|||||||
spice_server_remove_interface (&out->sin.base);
|
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);
|
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
|
||||||
int rpos, decr;
|
size_t rpos, decr;
|
||||||
int samples;
|
size_t samples;
|
||||||
|
|
||||||
if (!live) {
|
if (!live) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
decr = rate_get_samples (&hw->info, &out->rate);
|
decr = rate_get_samples (&hw->info, &out->rate);
|
||||||
decr = audio_MIN (live, decr);
|
decr = MIN (live, decr);
|
||||||
|
|
||||||
samples = decr;
|
samples = decr;
|
||||||
rpos = hw->rpos;
|
rpos = hw->rpos;
|
||||||
while (samples) {
|
while (samples) {
|
||||||
int left_till_end_samples = hw->samples - rpos;
|
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) {
|
if (!out->frame) {
|
||||||
spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
|
spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
|
||||||
out->fpos = out->frame;
|
out->fpos = out->frame;
|
||||||
}
|
}
|
||||||
if (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);
|
hw->clip (out->fpos, hw->mix_buf + rpos, len);
|
||||||
out->fsize -= len;
|
out->fsize -= len;
|
||||||
out->fpos += len;
|
out->fpos += len;
|
||||||
@ -192,11 +192,6 @@ static int line_out_run (HWVoiceOut *hw, int live)
|
|||||||
return decr;
|
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, ...)
|
static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
|
||||||
{
|
{
|
||||||
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
|
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);
|
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);
|
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
|
||||||
int num_samples;
|
size_t num_samples;
|
||||||
int ready;
|
int ready;
|
||||||
int len[2];
|
size_t len[2];
|
||||||
uint64_t delta_samp;
|
uint64_t delta_samp;
|
||||||
const uint32_t *samples;
|
const uint32_t *samples;
|
||||||
|
|
||||||
@ -294,7 +289,7 @@ static int line_in_run (HWVoiceIn *hw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
delta_samp = rate_get_samples (&hw->info, &in->rate);
|
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);
|
ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
|
||||||
samples = in->samples;
|
samples = in->samples;
|
||||||
@ -304,7 +299,7 @@ static int line_in_run (HWVoiceIn *hw)
|
|||||||
ready = LINE_IN_SAMPLES;
|
ready = LINE_IN_SAMPLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_samples = audio_MIN (ready, num_samples);
|
num_samples = MIN (ready, num_samples);
|
||||||
|
|
||||||
if (hw->wpos + num_samples > hw->samples) {
|
if (hw->wpos + num_samples > hw->samples) {
|
||||||
len[0] = hw->samples - hw->wpos;
|
len[0] = hw->samples - hw->wpos;
|
||||||
@ -325,11 +320,6 @@ static int line_in_run (HWVoiceIn *hw)
|
|||||||
return num_samples;
|
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, ...)
|
static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
|
||||||
{
|
{
|
||||||
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
|
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
|
||||||
@ -377,13 +367,11 @@ static struct audio_pcm_ops audio_callbacks = {
|
|||||||
.init_out = line_out_init,
|
.init_out = line_out_init,
|
||||||
.fini_out = line_out_fini,
|
.fini_out = line_out_fini,
|
||||||
.run_out = line_out_run,
|
.run_out = line_out_run,
|
||||||
.write = line_out_write,
|
|
||||||
.ctl_out = line_out_ctl,
|
.ctl_out = line_out_ctl,
|
||||||
|
|
||||||
.init_in = line_in_init,
|
.init_in = line_in_init,
|
||||||
.fini_in = line_in_fini,
|
.fini_in = line_in_fini,
|
||||||
.run_in = line_in_run,
|
.run_in = line_in_run,
|
||||||
.read = line_in_read,
|
|
||||||
.ctl_in = line_in_ctl,
|
.ctl_in = line_in_ctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,10 +40,10 @@ typedef struct WAVVoiceOut {
|
|||||||
int total_samples;
|
int total_samples;
|
||||||
} WAVVoiceOut;
|
} 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;
|
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
|
||||||
int rpos, decr, samples;
|
size_t rpos, decr, samples;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
struct st_sample *src;
|
struct st_sample *src;
|
||||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
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;
|
wav->old_ticks = now;
|
||||||
decr = audio_MIN (live, samples);
|
decr = MIN (live, samples);
|
||||||
samples = decr;
|
samples = decr;
|
||||||
rpos = hw->rpos;
|
rpos = hw->rpos;
|
||||||
while (samples) {
|
while (samples) {
|
||||||
int left_till_end_samples = hw->samples - rpos;
|
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;
|
src = hw->mix_buf + rpos;
|
||||||
dst = advance (wav->pcm_buf, rpos << hw->info.shift);
|
dst = advance (wav->pcm_buf, rpos << hw->info.shift);
|
||||||
@ -84,11 +84,6 @@ static int wav_run_out (HWVoiceOut *hw, int live)
|
|||||||
return decr;
|
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. */
|
/* VICE code: Store number as little endian. */
|
||||||
static void le_store (uint8_t *buf, uint32_t val, int len)
|
static void le_store (uint8_t *buf, uint32_t val, int len)
|
||||||
{
|
{
|
||||||
@ -144,7 +139,7 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
hw->samples = 1024;
|
hw->samples = 1024;
|
||||||
wav->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
wav->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
|
||||||
if (!wav->pcm_buf) {
|
if (!wav->pcm_buf) {
|
||||||
dolog ("Could not allocate buffer (%d bytes)\n",
|
dolog("Could not allocate buffer (%zu bytes)\n",
|
||||||
hw->samples << hw->info.shift);
|
hw->samples << hw->info.shift);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -240,7 +235,6 @@ static struct audio_pcm_ops wav_pcm_ops = {
|
|||||||
.init_out = wav_init_out,
|
.init_out = wav_init_out,
|
||||||
.fini_out = wav_fini_out,
|
.fini_out = wav_fini_out,
|
||||||
.run_out = wav_run_out,
|
.run_out = wav_run_out,
|
||||||
.write = wav_write_out,
|
|
||||||
.ctl_out = wav_ctl_out,
|
.ctl_out = wav_ctl_out,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,8 +104,8 @@ static struct capture_ops wav_capture_ops = {
|
|||||||
.info = wav_capture_info
|
.info = wav_capture_info
|
||||||
};
|
};
|
||||||
|
|
||||||
int wav_start_capture (CaptureState *s, const char *path, int freq,
|
int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
|
||||||
int bits, int nchannels)
|
int freq, int bits, int nchannels)
|
||||||
{
|
{
|
||||||
WAVState *wav;
|
WAVState *wav;
|
||||||
uint8_t hdr[] = {
|
uint8_t hdr[] = {
|
||||||
@ -170,7 +170,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
|||||||
goto error_free;
|
goto error_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
cap = AUD_add_capture (&as, &ops, wav);
|
cap = AUD_add_capture(state, &as, &ops, wav);
|
||||||
if (!cap) {
|
if (!cap) {
|
||||||
error_report("Failed to add audio capture");
|
error_report("Failed to add audio capture");
|
||||||
goto error_free;
|
goto error_free;
|
||||||
|
@ -819,16 +819,17 @@ ETEXI
|
|||||||
|
|
||||||
{
|
{
|
||||||
.name = "wavcapture",
|
.name = "wavcapture",
|
||||||
.args_type = "path:F,freq:i?,bits:i?,nchannels:i?",
|
.args_type = "path:F,audiodev:s,freq:i?,bits:i?,nchannels:i?",
|
||||||
.params = "path [frequency [bits [channels]]]",
|
.params = "path audiodev [frequency [bits [channels]]]",
|
||||||
.help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)",
|
.help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)",
|
||||||
.cmd = hmp_wavcapture,
|
.cmd = hmp_wavcapture,
|
||||||
},
|
},
|
||||||
STEXI
|
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
|
@findex wavcapture
|
||||||
Capture audio into @var{filename}. Using sample rate @var{frequency}
|
Capture audio into @var{filename} from @var{audiodev}, using sample rate
|
||||||
bits per sample @var{bits} and number of channels @var{channels}.
|
@var{frequency} bits per sample @var{bits} and number of channels
|
||||||
|
@var{channels}.
|
||||||
|
|
||||||
Defaults:
|
Defaults:
|
||||||
@itemize @minus
|
@itemize @minus
|
||||||
|
@ -965,7 +965,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
|||||||
uint32_t temp = r->picb << 1;
|
uint32_t temp = r->picb << 1;
|
||||||
uint32_t written = 0;
|
uint32_t written = 0;
|
||||||
int to_copy = 0;
|
int to_copy = 0;
|
||||||
temp = audio_MIN (temp, max);
|
temp = MIN (temp, max);
|
||||||
|
|
||||||
if (!temp) {
|
if (!temp) {
|
||||||
*stop = 1;
|
*stop = 1;
|
||||||
@ -974,7 +974,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
|||||||
|
|
||||||
while (temp) {
|
while (temp) {
|
||||||
int copied;
|
int copied;
|
||||||
to_copy = audio_MIN (temp, sizeof (tmpbuf));
|
to_copy = MIN (temp, sizeof (tmpbuf));
|
||||||
pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
|
pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
|
||||||
copied = AUD_write (s->voice_po, tmpbuf, to_copy);
|
copied = AUD_write (s->voice_po, tmpbuf, to_copy);
|
||||||
dolog ("write_audio max=%x to_copy=%x copied=%x\n",
|
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) {
|
while (elapsed) {
|
||||||
int temp = audio_MIN (elapsed, sizeof (s->silence));
|
int temp = MIN (elapsed, sizeof (s->silence));
|
||||||
while (temp) {
|
while (temp) {
|
||||||
int copied = AUD_write (s->voice_po, s->silence, temp);
|
int copied = AUD_write (s->voice_po, s->silence, temp);
|
||||||
if (!copied)
|
if (!copied)
|
||||||
@ -1041,7 +1041,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
|||||||
int to_copy = 0;
|
int to_copy = 0;
|
||||||
SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
|
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) {
|
if (!temp) {
|
||||||
*stop = 1;
|
*stop = 1;
|
||||||
@ -1050,7 +1050,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
|
|||||||
|
|
||||||
while (temp) {
|
while (temp) {
|
||||||
int acquired;
|
int acquired;
|
||||||
to_copy = audio_MIN (temp, sizeof (tmpbuf));
|
to_copy = MIN (temp, sizeof (tmpbuf));
|
||||||
acquired = AUD_read (voice, tmpbuf, to_copy);
|
acquired = AUD_read (voice, tmpbuf, to_copy);
|
||||||
if (!acquired) {
|
if (!acquired) {
|
||||||
*stop = 1;
|
*stop = 1;
|
||||||
@ -1410,6 +1410,7 @@ static int ac97_init (PCIBus *bus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Property ac97_properties[] = {
|
static Property ac97_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(AC97LinkState, card),
|
||||||
DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
|
DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
|
||||||
DEFINE_PROP_END_OF_LIST (),
|
DEFINE_PROP_END_OF_LIST (),
|
||||||
};
|
};
|
||||||
|
@ -195,7 +195,7 @@ static void adlib_callback (void *opaque, int free)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
to_play = audio_MIN (s->left, samples);
|
to_play = MIN (s->left, samples);
|
||||||
while (to_play) {
|
while (to_play) {
|
||||||
written = write_audio (s, 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) {
|
if (!samples) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -299,6 +299,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Property adlib_properties[] = {
|
static Property adlib_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(AdlibState, card),
|
||||||
DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220),
|
DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220),
|
||||||
DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100),
|
DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100),
|
||||||
DEFINE_PROP_END_OF_LIST (),
|
DEFINE_PROP_END_OF_LIST (),
|
||||||
|
@ -536,7 +536,7 @@ static int cs_write_audio (CSState *s, int nchan, int dma_pos,
|
|||||||
int copied;
|
int copied;
|
||||||
size_t to_copy;
|
size_t to_copy;
|
||||||
|
|
||||||
to_copy = audio_MIN (temp, left);
|
to_copy = MIN (temp, left);
|
||||||
if (to_copy > sizeof (tmpbuf)) {
|
if (to_copy > sizeof (tmpbuf)) {
|
||||||
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]
|
till = (s->dregs[Playback_Lower_Base_Count]
|
||||||
| (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
|
| (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
|
||||||
till -= s->transferred;
|
till -= s->transferred;
|
||||||
copy = audio_MIN (till, copy);
|
copy = MIN (till, copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((copy <= 0) || (dma_len <= 0)) {
|
if ((copy <= 0) || (dma_len <= 0)) {
|
||||||
@ -690,6 +690,7 @@ static int cs4231a_init (ISABus *bus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Property cs4231a_properties[] = {
|
static Property cs4231a_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(CSState, card),
|
||||||
DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
|
DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
|
||||||
DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
|
DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
|
||||||
DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
|
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 size = d->frame_cnt & 0xffff;
|
||||||
int left = ((size - cnt + 1) << 2) + d->leftover;
|
int left = ((size - cnt + 1) << 2) + d->leftover;
|
||||||
int transferred = 0;
|
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];
|
int index = d - &s->chan[0];
|
||||||
|
|
||||||
addr += (cnt << 2) + d->leftover;
|
addr += (cnt << 2) + d->leftover;
|
||||||
@ -654,7 +654,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
|||||||
while (temp) {
|
while (temp) {
|
||||||
int acquired, to_copy;
|
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);
|
acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
|
||||||
if (!acquired)
|
if (!acquired)
|
||||||
break;
|
break;
|
||||||
@ -672,7 +672,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
|||||||
while (temp) {
|
while (temp) {
|
||||||
int copied, to_copy;
|
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);
|
pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
|
||||||
copied = AUD_write (voice, tmpbuf, to_copy);
|
copied = AUD_write (voice, tmpbuf, to_copy);
|
||||||
if (!copied)
|
if (!copied)
|
||||||
@ -887,6 +887,11 @@ static int es1370_init (PCIBus *bus)
|
|||||||
return 0;
|
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)
|
static void es1370_class_init (ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS (klass);
|
DeviceClass *dc = DEVICE_CLASS (klass);
|
||||||
@ -903,6 +908,7 @@ static void es1370_class_init (ObjectClass *klass, void *data)
|
|||||||
dc->desc = "ENSONIQ AudioPCI ES1370";
|
dc->desc = "ENSONIQ AudioPCI ES1370";
|
||||||
dc->vmsd = &vmstate_es1370;
|
dc->vmsd = &vmstate_es1370;
|
||||||
dc->reset = es1370_on_reset;
|
dc->reset = es1370_on_reset;
|
||||||
|
dc->props = es1370_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo es1370_info = {
|
static const TypeInfo es1370_info = {
|
||||||
@ -923,4 +929,3 @@ static void es1370_register_types (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
type_init (es1370_register_types)
|
type_init (es1370_register_types)
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ static void GUS_callback (void *opaque, int free)
|
|||||||
GUSState *s = opaque;
|
GUSState *s = opaque;
|
||||||
|
|
||||||
samples = free >> s->shift;
|
samples = free >> s->shift;
|
||||||
to_play = audio_MIN (samples, s->left);
|
to_play = MIN (samples, s->left);
|
||||||
|
|
||||||
while (to_play) {
|
while (to_play) {
|
||||||
int written = write_audio (s, to_play);
|
int written = write_audio (s, to_play);
|
||||||
@ -134,7 +134,7 @@ static void GUS_callback (void *opaque, int free)
|
|||||||
net += written;
|
net += written;
|
||||||
}
|
}
|
||||||
|
|
||||||
samples = audio_MIN (samples, s->samples);
|
samples = MIN (samples, s->samples);
|
||||||
if (samples) {
|
if (samples) {
|
||||||
gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
|
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);
|
ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
|
||||||
mode = k->has_autoinitialization(s->isa_dma, s->emu.gusdma);
|
mode = k->has_autoinitialization(s->isa_dma, s->emu.gusdma);
|
||||||
while (left) {
|
while (left) {
|
||||||
int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
|
int to_copy = MIN ((size_t) left, sizeof (tmpbuf));
|
||||||
int copied;
|
int copied;
|
||||||
|
|
||||||
ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
|
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[] = {
|
static Property gus_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(GUSState, card),
|
||||||
DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
|
DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
|
||||||
DEFINE_PROP_UINT32 ("iobase", GUSState, port, 0x240),
|
DEFINE_PROP_UINT32 ("iobase", GUSState, port, 0x240),
|
||||||
DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
|
DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
|
||||||
|
@ -235,10 +235,10 @@ static void hda_audio_input_timer(void *opaque)
|
|||||||
goto out_timer;
|
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) {
|
while (to_transfer) {
|
||||||
uint32_t start = (rpos & B_MASK);
|
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(
|
int rc = hda_codec_xfer(
|
||||||
&st->state->hda, st->stream, false, st->buf + start, chunk);
|
&st->state->hda, st->stream, false, st->buf + start, chunk);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
@ -263,13 +263,13 @@ static void hda_audio_input_cb(void *opaque, int avail)
|
|||||||
int64_t wpos = st->wpos;
|
int64_t wpos = st->wpos;
|
||||||
int64_t rpos = st->rpos;
|
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)));
|
hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1)));
|
||||||
|
|
||||||
while (to_transfer) {
|
while (to_transfer) {
|
||||||
uint32_t start = (uint32_t) (wpos & B_MASK);
|
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);
|
uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk);
|
||||||
wpos += read;
|
wpos += read;
|
||||||
to_transfer -= read;
|
to_transfer -= read;
|
||||||
@ -299,10 +299,10 @@ static void hda_audio_output_timer(void *opaque)
|
|||||||
goto out_timer;
|
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) {
|
while (to_transfer) {
|
||||||
uint32_t start = (wpos & B_MASK);
|
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(
|
int rc = hda_codec_xfer(
|
||||||
&st->state->hda, st->stream, true, st->buf + start, chunk);
|
&st->state->hda, st->stream, true, st->buf + start, chunk);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
@ -327,7 +327,7 @@ static void hda_audio_output_cb(void *opaque, int avail)
|
|||||||
int64_t wpos = st->wpos;
|
int64_t wpos = st->wpos;
|
||||||
int64_t rpos = st->rpos;
|
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) {
|
if (wpos - rpos == B_SIZE) {
|
||||||
/* drop buffer, reset timer adjust */
|
/* drop buffer, reset timer adjust */
|
||||||
@ -342,7 +342,7 @@ static void hda_audio_output_cb(void *opaque, int avail)
|
|||||||
|
|
||||||
while (to_transfer) {
|
while (to_transfer) {
|
||||||
uint32_t start = (uint32_t) (rpos & B_MASK);
|
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);
|
uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk);
|
||||||
rpos += written;
|
rpos += written;
|
||||||
to_transfer -= written;
|
to_transfer -= written;
|
||||||
@ -841,6 +841,7 @@ static const VMStateDescription vmstate_hda_audio = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Property hda_audio_properties[] = {
|
static Property hda_audio_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(HDAAudioState, card),
|
||||||
DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
|
DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
|
||||||
DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
|
DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
|
||||||
DEFINE_PROP_BOOL("use-timer", HDAAudioState, use_timer, 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;
|
MilkymistAC97State *s = opaque;
|
||||||
uint8_t buf[4096];
|
uint8_t buf[4096];
|
||||||
uint32_t remaining = s->regs[R_U_REMAINING];
|
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];
|
uint32_t addr = s->regs[R_U_ADDR];
|
||||||
int transferred = 0;
|
int transferred = 0;
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ static void ac97_in_cb(void *opaque, int avail_b)
|
|||||||
while (temp) {
|
while (temp) {
|
||||||
int acquired, to_copy;
|
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);
|
acquired = AUD_read(s->voice_in, buf, to_copy);
|
||||||
if (!acquired) {
|
if (!acquired) {
|
||||||
break;
|
break;
|
||||||
@ -228,7 +228,7 @@ static void ac97_out_cb(void *opaque, int free_b)
|
|||||||
MilkymistAC97State *s = opaque;
|
MilkymistAC97State *s = opaque;
|
||||||
uint8_t buf[4096];
|
uint8_t buf[4096];
|
||||||
uint32_t remaining = s->regs[R_D_REMAINING];
|
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];
|
uint32_t addr = s->regs[R_D_ADDR];
|
||||||
int transferred = 0;
|
int transferred = 0;
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ static void ac97_out_cb(void *opaque, int free_b)
|
|||||||
while (temp) {
|
while (temp) {
|
||||||
int copied, to_copy;
|
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);
|
cpu_physical_memory_read(addr, buf, to_copy);
|
||||||
copied = AUD_write(s->voice_out, buf, to_copy);
|
copied = AUD_write(s->voice_out, buf, to_copy);
|
||||||
if (!copied) {
|
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)
|
static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
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->realize = milkymist_ac97_realize;
|
||||||
dc->reset = milkymist_ac97_reset;
|
dc->reset = milkymist_ac97_reset;
|
||||||
dc->vmsd = &vmstate_milkymist_ac97;
|
dc->vmsd = &vmstate_milkymist_ac97;
|
||||||
|
dc->props = milkymist_ac97_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo milkymist_ac97_info = {
|
static const TypeInfo milkymist_ac97_info = {
|
||||||
|
@ -103,7 +103,7 @@ static void pcspk_callback(void *opaque, int free)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (free > 0) {
|
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);
|
n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
|
||||||
if (!n)
|
if (!n)
|
||||||
break;
|
break;
|
||||||
@ -209,6 +209,7 @@ static const VMStateDescription vmstate_spk = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Property pcspk_properties[] = {
|
static Property pcspk_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(PCSpkState, card),
|
||||||
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
|
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
|
||||||
DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true),
|
DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
@ -625,6 +625,7 @@ static const VMStateDescription vmstate_pl041 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Property pl041_device_properties[] = {
|
static Property pl041_device_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(PL041State, codec.card),
|
||||||
/* Non-compact FIFO depth property */
|
/* Non-compact FIFO depth property */
|
||||||
DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth,
|
DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth,
|
||||||
DEFAULT_FIFO_DEPTH),
|
DEFAULT_FIFO_DEPTH),
|
||||||
|
@ -1169,7 +1169,7 @@ static int write_audio (SB16State *s, int nchan, int dma_pos,
|
|||||||
int copied;
|
int copied;
|
||||||
size_t to_copy;
|
size_t to_copy;
|
||||||
|
|
||||||
to_copy = audio_MIN (temp, left);
|
to_copy = MIN (temp, left);
|
||||||
if (to_copy > sizeof (tmpbuf)) {
|
if (to_copy > sizeof (tmpbuf)) {
|
||||||
to_copy = sizeof (tmpbuf);
|
to_copy = sizeof (tmpbuf);
|
||||||
}
|
}
|
||||||
@ -1422,6 +1422,7 @@ static int SB16_init (ISABus *bus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Property sb16_properties[] = {
|
static Property sb16_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(SB16State, card),
|
||||||
DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
|
DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
|
||||||
DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
|
DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
|
||||||
DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
|
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))
|
if (s->idx_in + s->req_in <= sizeof(s->data_in))
|
||||||
return;
|
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,
|
AUD_read(*s->in[0], s->data_in + s->idx_in,
|
||||||
sizeof(s->data_in) - s->idx_in);
|
sizeof(s->data_in) - s->idx_in);
|
||||||
}
|
}
|
||||||
@ -702,6 +702,11 @@ void wm8750_set_bclk_in(void *opaque, int new_hz)
|
|||||||
wm8750_clk_update(s, 1);
|
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)
|
static void wm8750_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
@ -712,6 +717,7 @@ static void wm8750_class_init(ObjectClass *klass, void *data)
|
|||||||
sc->recv = wm8750_rx;
|
sc->recv = wm8750_rx;
|
||||||
sc->send = wm8750_tx;
|
sc->send = wm8750_tx;
|
||||||
dc->vmsd = &vmstate_wm8750;
|
dc->vmsd = &vmstate_wm8750;
|
||||||
|
dc->props = wm8750_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo wm8750_info = {
|
static const TypeInfo wm8750_info = {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "audio/audio.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
#include "qapi/error.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,
|
void qdev_prop_set_drive(DeviceState *dev, const char *name,
|
||||||
BlockBackend *value, Error **errp)
|
BlockBackend *value, Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -667,6 +667,7 @@ static const VMStateDescription vmstate_usb_audio = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Property usb_audio_properties[] = {
|
static Property usb_audio_properties[] = {
|
||||||
|
DEFINE_AUDIO_PROPERTIES(USBAudioState, card),
|
||||||
DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
|
DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
|
||||||
DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
|
DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
|
||||||
32 * USBAUDIO_PACKET_SIZE),
|
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_pci_host_devaddr;
|
||||||
extern const PropertyInfo qdev_prop_uuid;
|
extern const PropertyInfo qdev_prop_uuid;
|
||||||
extern const PropertyInfo qdev_prop_arraylen;
|
extern const PropertyInfo qdev_prop_arraylen;
|
||||||
|
extern const PropertyInfo qdev_prop_audiodev;
|
||||||
extern const PropertyInfo qdev_prop_link;
|
extern const PropertyInfo qdev_prop_link;
|
||||||
extern const PropertyInfo qdev_prop_off_auto_pcibar;
|
extern const PropertyInfo qdev_prop_off_auto_pcibar;
|
||||||
extern const PropertyInfo qdev_prop_pcie_link_speed;
|
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)), \
|
+ type_check(QemuUUID, typeof_field(_state, _field)), \
|
||||||
.set_default = true, \
|
.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() \
|
#define DEFINE_PROP_END_OF_LIST() \
|
||||||
{}
|
{}
|
||||||
|
@ -179,9 +179,9 @@ void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
|
|||||||
/* Audio */
|
/* Audio */
|
||||||
|
|
||||||
/*! Saves/restores number of played samples of audio out operation. */
|
/*! 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. */
|
/*! 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 */
|
/* 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)
|
static void hmp_wavcapture(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *path = qdict_get_str(qdict, "path");
|
const char *path = qdict_get_str(qdict, "path");
|
||||||
int has_freq = qdict_haskey(qdict, "freq");
|
int freq = qdict_get_try_int(qdict, "freq", 44100);
|
||||||
int freq = qdict_get_try_int(qdict, "freq", -1);
|
int bits = qdict_get_try_int(qdict, "bits", 16);
|
||||||
int has_bits = qdict_haskey(qdict, "bits");
|
int nchannels = qdict_get_try_int(qdict, "nchannels", 2);
|
||||||
int bits = qdict_get_try_int(qdict, "bits", -1);
|
const char *audiodev = qdict_get_str(qdict, "audiodev");
|
||||||
int has_channels = qdict_haskey(qdict, "nchannels");
|
|
||||||
int nchannels = qdict_get_try_int(qdict, "nchannels", -1);
|
|
||||||
CaptureState *s;
|
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));
|
s = g_malloc0 (sizeof (*s));
|
||||||
|
|
||||||
freq = has_freq ? freq : 44100;
|
if (wav_start_capture(as, s, path, freq, bits, nchannels)) {
|
||||||
bits = has_bits ? bits : 16;
|
|
||||||
nchannels = has_channels ? nchannels : 2;
|
|
||||||
|
|
||||||
if (wav_start_capture (s, path, freq, bits, nchannels)) {
|
|
||||||
monitor_printf(mon, "Failed to add wave capture\n");
|
monitor_printf(mon, "Failed to add wave capture\n");
|
||||||
g_free (s);
|
g_free (s);
|
||||||
return;
|
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
|
events are arriving in bulk. Possible causes for the latter are flaky
|
||||||
network connections, or scripts for automated testing.
|
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
|
@end table
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
|
@ -15,18 +15,18 @@
|
|||||||
#include "replay-internal.h"
|
#include "replay-internal.h"
|
||||||
#include "audio/audio.h"
|
#include "audio/audio.h"
|
||||||
|
|
||||||
void replay_audio_out(int *played)
|
void replay_audio_out(size_t *played)
|
||||||
{
|
{
|
||||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||||
g_assert(replay_mutex_locked());
|
g_assert(replay_mutex_locked());
|
||||||
replay_save_instructions();
|
replay_save_instructions();
|
||||||
replay_put_event(EVENT_AUDIO_OUT);
|
replay_put_event(EVENT_AUDIO_OUT);
|
||||||
replay_put_dword(*played);
|
replay_put_qword(*played);
|
||||||
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||||
g_assert(replay_mutex_locked());
|
g_assert(replay_mutex_locked());
|
||||||
replay_account_executed_instructions();
|
replay_account_executed_instructions();
|
||||||
if (replay_next_event_is(EVENT_AUDIO_OUT)) {
|
if (replay_next_event_is(EVENT_AUDIO_OUT)) {
|
||||||
*played = replay_get_dword();
|
*played = replay_get_qword();
|
||||||
replay_finish_event();
|
replay_finish_event();
|
||||||
} else {
|
} else {
|
||||||
error_report("Missing audio out event in the replay log");
|
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;
|
int pos;
|
||||||
uint64_t left, right;
|
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());
|
g_assert(replay_mutex_locked());
|
||||||
replay_save_instructions();
|
replay_save_instructions();
|
||||||
replay_put_event(EVENT_AUDIO_IN);
|
replay_put_event(EVENT_AUDIO_IN);
|
||||||
replay_put_dword(*recorded);
|
replay_put_qword(*recorded);
|
||||||
replay_put_dword(*wpos);
|
replay_put_qword(*wpos);
|
||||||
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
||||||
; pos = (pos + 1) % size) {
|
; pos = (pos + 1) % size) {
|
||||||
audio_sample_to_uint64(samples, pos, &left, &right);
|
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());
|
g_assert(replay_mutex_locked());
|
||||||
replay_account_executed_instructions();
|
replay_account_executed_instructions();
|
||||||
if (replay_next_event_is(EVENT_AUDIO_IN)) {
|
if (replay_next_event_is(EVENT_AUDIO_IN)) {
|
||||||
*recorded = replay_get_dword();
|
*recorded = replay_get_qword();
|
||||||
*wpos = replay_get_dword();
|
*wpos = replay_get_qword();
|
||||||
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
||||||
; pos = (pos + 1) % size) {
|
; pos = (pos + 1) % size) {
|
||||||
left = replay_get_qword();
|
left = replay_get_qword();
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
/* Current version of the replay mechanism.
|
/* Current version of the replay mechanism.
|
||||||
Increase it when file format changes. */
|
Increase it when file format changes. */
|
||||||
#define REPLAY_VERSION 0xe02007
|
#define REPLAY_VERSION 0xe02008
|
||||||
/* Size of replay log header */
|
/* Size of replay log header */
|
||||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
#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.destroy = audio_capture_destroy;
|
||||||
ops.capture = audio_capture;
|
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) {
|
if (!vs->audio_cap) {
|
||||||
error_report("Failed to add audio capture");
|
error_report("Failed to add audio capture");
|
||||||
}
|
}
|
||||||
@ -3371,6 +3371,9 @@ static QemuOptsList qemu_vnc_opts = {
|
|||||||
},{
|
},{
|
||||||
.name = "non-adaptive",
|
.name = "non-adaptive",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
|
},{
|
||||||
|
.name = "audiodev",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
@ -3808,6 +3811,7 @@ void vnc_display_open(const char *id, Error **errp)
|
|||||||
const char *saslauthz;
|
const char *saslauthz;
|
||||||
int lock_key_sync = 1;
|
int lock_key_sync = 1;
|
||||||
int key_delay_ms;
|
int key_delay_ms;
|
||||||
|
const char *audiodev;
|
||||||
|
|
||||||
if (!vd) {
|
if (!vd) {
|
||||||
error_setg(errp, "VNC display not active");
|
error_setg(errp, "VNC display not active");
|
||||||
@ -3993,6 +3997,15 @@ void vnc_display_open(const char *id, Error **errp)
|
|||||||
}
|
}
|
||||||
vd->ledstate = 0;
|
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");
|
device_id = qemu_opt_get(opts, "display");
|
||||||
if (device_id) {
|
if (device_id) {
|
||||||
int head = qemu_opt_get_number(opts, "head", 0);
|
int head = qemu_opt_get_number(opts, "head", 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user