aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-02-07 13:42:09 +0000
committerPeter Maydell <peter.maydell@linaro.org>2020-02-07 13:42:09 +0000
commitb6bef1147f0f4edb7d8aac1e26d9511898ae854d (patch)
treeccacabee62a6fab86ec0a92386eba3fee33fb849
parent346ed3151f1c43e72c40cb55b392a1d4cface62c (diff)
parented2a4a794184df3dbd5ee4cc06e86fe220663faf (diff)
downloadqemu-b6bef1147f0f4edb7d8aac1e26d9511898ae854d.zip
qemu-b6bef1147f0f4edb7d8aac1e26d9511898ae854d.tar.gz
qemu-b6bef1147f0f4edb7d8aac1e26d9511898ae854d.tar.bz2
Merge remote-tracking branch 'remotes/kraxel/tags/audio-20200207-pull-request' into staging
audio: bugfixes, mostly audio backend rewrite fallout # gpg: Signature made Fri 07 Feb 2020 07:45:44 GMT # 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-20200207-pull-request: audio: proper support for float samples in mixeng coreaudio: fix coreaudio playback audio/dsound: fix invalid parameters error audio: audio_generic_get_buffer_in should honor *size ossaudio: disable poll mode can't be reached ossaudio: prevent SIGSEGV in oss_enable_out audio: fix bug 1858488 audio: prevent SIGSEGV in AUD_get_buffer_size_out paaudio: remove unused variables audio: fix audio_generic_read audio: fix audio_generic_write audio/oss: fix buffer pos calculation Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--audio/alsaaudio.c18
-rw-r--r--audio/audio.c139
-rw-r--r--audio/audio_int.h7
-rw-r--r--audio/audio_template.h40
-rw-r--r--audio/coreaudio.c34
-rw-r--r--audio/dsound_template.h1
-rw-r--r--audio/dsoundaudio.c27
-rw-r--r--audio/mixeng.c70
-rw-r--r--audio/mixeng.h5
-rw-r--r--audio/noaudio.c1
-rw-r--r--audio/ossaudio.c28
-rw-r--r--audio/paaudio.c15
-rw-r--r--audio/sdlaudio.c35
-rw-r--r--audio/wavaudio.c1
-rw-r--r--qapi/audio.json2
15 files changed, 299 insertions, 124 deletions
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index f37ce1c..a23a5a0 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -307,6 +307,13 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
return SND_PCM_FORMAT_U32_LE;
}
+ case AUDIO_FORMAT_F32:
+ if (endianness) {
+ return SND_PCM_FORMAT_FLOAT_BE;
+ } else {
+ return SND_PCM_FORMAT_FLOAT_LE;
+ }
+
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
@@ -370,6 +377,16 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
*fmt = AUDIO_FORMAT_U32;
break;
+ case SND_PCM_FORMAT_FLOAT_LE:
+ *endianness = 0;
+ *fmt = AUDIO_FORMAT_F32;
+ break;
+
+ case SND_PCM_FORMAT_FLOAT_BE:
+ *endianness = 1;
+ *fmt = AUDIO_FORMAT_F32;
+ break;
+
default:
dolog ("Unrecognized audio format %d\n", alsafmt);
return -1;
@@ -906,6 +923,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out,
.fini_out = alsa_fini_out,
.write = alsa_write,
+ .run_buffer_out = audio_generic_run_buffer_out,
.enable_out = alsa_enable_out,
.init_in = alsa_init_in,
diff --git a/audio/audio.c b/audio/audio.c
index f63f397..9ac9a20 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -218,6 +218,9 @@ static void audio_print_settings (struct audsettings *as)
case AUDIO_FORMAT_U32:
AUD_log (NULL, "U32");
break;
+ case AUDIO_FORMAT_F32:
+ AUD_log (NULL, "F32");
+ break;
default:
AUD_log (NULL, "invalid(%d)", as->fmt);
break;
@@ -252,6 +255,7 @@ static int audio_validate_settings (struct audsettings *as)
case AUDIO_FORMAT_U16:
case AUDIO_FORMAT_S32:
case AUDIO_FORMAT_U32:
+ case AUDIO_FORMAT_F32:
break;
default:
invalid = 1;
@@ -264,24 +268,28 @@ static int audio_validate_settings (struct audsettings *as)
static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
{
- int bits = 8, sign = 0;
+ int bits = 8;
+ bool is_signed = false, is_float = false;
switch (as->fmt) {
case AUDIO_FORMAT_S8:
- sign = 1;
+ is_signed = true;
/* fall through */
case AUDIO_FORMAT_U8:
break;
case AUDIO_FORMAT_S16:
- sign = 1;
+ is_signed = true;
/* fall through */
case AUDIO_FORMAT_U16:
bits = 16;
break;
+ case AUDIO_FORMAT_F32:
+ is_float = true;
+ /* fall through */
case AUDIO_FORMAT_S32:
- sign = 1;
+ is_signed = true;
/* fall through */
case AUDIO_FORMAT_U32:
bits = 32;
@@ -292,33 +300,38 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
}
return info->freq == as->freq
&& info->nchannels == as->nchannels
- && info->sign == sign
+ && info->is_signed == is_signed
+ && info->is_float == is_float
&& info->bits == bits
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
}
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
{
- int bits = 8, sign = 0, mul;
+ int bits = 8, mul;
+ bool is_signed = false, is_float = false;
switch (as->fmt) {
case AUDIO_FORMAT_S8:
- sign = 1;
+ is_signed = true;
/* fall through */
case AUDIO_FORMAT_U8:
mul = 1;
break;
case AUDIO_FORMAT_S16:
- sign = 1;
+ is_signed = true;
/* fall through */
case AUDIO_FORMAT_U16:
bits = 16;
mul = 2;
break;
+ case AUDIO_FORMAT_F32:
+ is_float = true;
+ /* fall through */
case AUDIO_FORMAT_S32:
- sign = 1;
+ is_signed = true;
/* fall through */
case AUDIO_FORMAT_U32:
bits = 32;
@@ -331,7 +344,8 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
info->freq = as->freq;
info->bits = bits;
- info->sign = sign;
+ info->is_signed = is_signed;
+ info->is_float = is_float;
info->nchannels = as->nchannels;
info->bytes_per_frame = as->nchannels * mul;
info->bytes_per_second = info->freq * info->bytes_per_frame;
@@ -344,7 +358,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
return;
}
- if (info->sign) {
+ if (info->is_signed || info->is_float) {
memset(buf, 0x00, len * info->bytes_per_frame);
}
else {
@@ -770,8 +784,9 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
#ifdef DEBUG_AUDIO
static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
{
- dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
- cap, info->bits, info->sign, info->freq, info->nchannels);
+ dolog("%s: bits %d, sign %d, float %d, freq %d, nchan %d\n",
+ cap, info->bits, info->is_signed, info->is_float, info->freq,
+ info->nchannels);
}
#endif
@@ -879,9 +894,9 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
}
}
-int AUD_get_buffer_size_out (SWVoiceOut *sw)
+int AUD_get_buffer_size_out(SWVoiceOut *sw)
{
- return sw->hw->mix_buf->size * sw->hw->info.bytes_per_frame;
+ return sw->hw->samples * sw->hw->info.bytes_per_frame;
}
void AUD_set_active_out (SWVoiceOut *sw, int on)
@@ -1076,10 +1091,8 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
while (live) {
size_t size, decr, proc;
void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
- if (!buf) {
- /* retrying will likely won't help, drop everything. */
- hw->mix_buf->pos = (hw->mix_buf->pos + live) % hw->mix_buf->size;
- return clipped + live;
+ if (!buf || size == 0) {
+ break;
}
decr = MIN(size / hw->info.bytes_per_frame, live);
@@ -1097,6 +1110,10 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
}
}
+ if (hw->pcm_ops->run_buffer_out) {
+ hw->pcm_ops->run_buffer_out(hw);
+ }
+
return clipped;
}
@@ -1403,7 +1420,8 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
}
assert(start >= 0 && start < hw->size_emul);
- *size = MIN(hw->pending_emul, hw->size_emul - start);
+ *size = MIN(*size, hw->pending_emul);
+ *size = MIN(*size, hw->size_emul - start);
return hw->buf_emul + start;
}
@@ -1413,6 +1431,28 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
hw->pending_emul -= size;
}
+void audio_generic_run_buffer_out(HWVoiceOut *hw)
+{
+ while (hw->pending_emul) {
+ size_t write_len, written;
+ ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
+
+ write_len = MIN(hw->pending_emul, hw->size_emul - start);
+
+ written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
+ hw->pending_emul -= written;
+
+ if (written < write_len) {
+ break;
+ }
+ }
+}
+
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
if (unlikely(!hw->buf_emul)) {
@@ -1428,8 +1468,7 @@ void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
return hw->buf_emul + hw->pos_emul;
}
-size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
- size_t size)
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
{
assert(buf == hw->buf_emul + hw->pos_emul &&
size + hw->pending_emul <= hw->size_emul);
@@ -1440,35 +1479,6 @@ size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
return size;
}
-size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
-{
- audio_generic_put_buffer_out_nowrite(hw, buf, size);
-
- while (hw->pending_emul) {
- size_t write_len, written;
- ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
- if (start < 0) {
- start += hw->size_emul;
- }
- assert(start >= 0 && start < hw->size_emul);
-
- write_len = MIN(hw->pending_emul, hw->size_emul - start);
-
- written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
- hw->pending_emul -= written;
-
- if (written < write_len) {
- break;
- }
- }
-
- /*
- * fake we have written everything. non-written data remain in pending_emul,
- * so we do not have to clip them multiple times
- */
- return size;
-}
-
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
{
size_t dst_size, copy_size;
@@ -1476,17 +1486,17 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
copy_size = MIN(size, dst_size);
memcpy(dst, buf, copy_size);
- return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
+ return hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
}
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
{
- size_t dst_size, copy_size;
- void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
- copy_size = MIN(size, dst_size);
+ size_t src_size, copy_size;
+ void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);
+ copy_size = MIN(size, src_size);
- memcpy(dst, buf, copy_size);
- hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
+ memcpy(buf, src, copy_size);
+ hw->pcm_ops->put_buffer_in(hw, src, copy_size);
return copy_size;
}
@@ -1837,11 +1847,15 @@ CaptureVoiceOut *AUD_add_capture(
cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
- hw->clip = mixeng_clip
- [hw->info.nchannels == 2]
- [hw->info.sign]
- [hw->info.swap_endianness]
- [audio_bits_to_index (hw->info.bits)];
+ if (hw->info.is_float) {
+ hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
+ } else {
+ hw->clip = mixeng_clip
+ [hw->info.nchannels == 2]
+ [hw->info.is_signed]
+ [hw->info.swap_endianness]
+ [audio_bits_to_index(hw->info.bits)];
+ }
QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
@@ -2080,6 +2094,7 @@ int audioformat_bytes_per_sample(AudioFormat fmt)
case AUDIO_FORMAT_U32:
case AUDIO_FORMAT_S32:
+ case AUDIO_FORMAT_F32:
return 4;
case AUDIO_FORMAT__MAX:
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 5ba2078..4775857 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -40,7 +40,8 @@ struct audio_callback {
struct audio_pcm_info {
int bits;
- int sign;
+ bool is_signed;
+ bool is_float;
int freq;
int nchannels;
int bytes_per_frame;
@@ -152,6 +153,7 @@ struct audio_pcm_ops {
int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
void (*fini_out)(HWVoiceOut *hw);
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
+ void (*run_buffer_out)(HWVoiceOut *hw);
/*
* get a buffer that after later can be passed to put_buffer_out; optional
* returns the buffer, and writes it's size to size (in bytes)
@@ -178,10 +180,9 @@ struct audio_pcm_ops {
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
+void audio_generic_run_buffer_out(HWVoiceOut *hw);
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
-size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
- size_t size);
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 3287d70..7013d30 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -153,15 +153,23 @@ static int glue (audio_pcm_sw_init_, TYPE) (
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
#endif
+ if (sw->info.is_float) {
#ifdef DAC
- sw->conv = mixeng_conv
+ sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
#else
- sw->clip = mixeng_clip
+ sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
#endif
- [sw->info.nchannels == 2]
- [sw->info.sign]
- [sw->info.swap_endianness]
- [audio_bits_to_index (sw->info.bits)];
+ } else {
+#ifdef DAC
+ sw->conv = mixeng_conv
+#else
+ sw->clip = mixeng_clip
+#endif
+ [sw->info.nchannels == 2]
+ [sw->info.is_signed]
+ [sw->info.swap_endianness]
+ [audio_bits_to_index(sw->info.bits)];
+ }
sw->name = g_strdup (name);
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
@@ -276,15 +284,23 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
goto err1;
}
+ if (hw->info.is_float) {
#ifdef DAC
- hw->clip = mixeng_clip
+ hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
#else
- hw->conv = mixeng_conv
+ hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
#endif
- [hw->info.nchannels == 2]
- [hw->info.sign]
- [hw->info.swap_endianness]
- [audio_bits_to_index (hw->info.bits)];
+ } else {
+#ifdef DAC
+ hw->clip = mixeng_clip
+#else
+ hw->conv = mixeng_conv
+#endif
+ [hw->info.nchannels == 2]
+ [hw->info.is_signed]
+ [hw->info.swap_endianness]
+ [audio_bits_to_index(hw->info.bits)];
+ }
glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 66f0f45..4b43656 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -411,7 +411,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
}
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
(hw, size))
-COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
+COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
(HWVoiceOut *hw, void *buf, size_t size),
(hw, buf, size))
COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
@@ -471,20 +471,6 @@ static OSStatus audioDeviceIOProc(
return 0;
}
-static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
- struct audsettings *as)
-{
- UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
- if (as->endianness) { /* 0 = little, 1 = big */
- flags |= kAudioFormatFlagIsBigEndian;
- }
-
- if (flags == 0) { /* must not be 0 */
- flags = kAudioFormatFlagsAreAllClear;
- }
- return flags;
-}
-
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
@@ -496,6 +482,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
Audiodev *dev = drv_opaque;
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
int frames;
+ struct audsettings fake_as;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
@@ -504,6 +491,9 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
return -1;
}
+ fake_as = *as;
+ as = &fake_as;
+ as->fmt = AUDIO_FORMAT_F32;
audio_pcm_init_info (&hw->info, as);
status = coreaudio_get_voice(&core->outputDeviceID);
@@ -572,15 +562,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
/* set Samplerate */
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
- core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
- core->outputStreamBasicDescription.mFormatFlags =
- coreaudio_get_flags(&hw->info, as);
- core->outputStreamBasicDescription.mBytesPerPacket =
- core->outputStreamBasicDescription.mBytesPerFrame =
- hw->info.nchannels * hw->info.bits / 8;
- core->outputStreamBasicDescription.mFramesPerPacket = 1;
- core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
- core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;
status = coreaudio_set_streamformat(core->outputDeviceID,
&core->outputStreamBasicDescription);
@@ -687,9 +668,12 @@ static void coreaudio_audio_fini (void *opaque)
static struct audio_pcm_ops coreaudio_pcm_ops = {
.init_out = coreaudio_init_out,
.fini_out = coreaudio_fini_out,
+ /* wrapper for audio_generic_write */
.write = coreaudio_write,
+ /* wrapper for audio_generic_get_buffer_out */
.get_buffer_out = coreaudio_get_buffer_out,
- .put_buffer_out = coreaudio_put_buffer_out_nowrite,
+ /* wrapper for audio_generic_put_buffer_out */
+ .put_buffer_out = coreaudio_put_buffer_out,
.enable_out = coreaudio_enable_out
};
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index 7a15f91..9c5ce62 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -244,6 +244,7 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
goto fail0;
}
+ ds->first_time = true;
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index c265c00..bd57082 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -53,12 +53,14 @@ typedef struct {
typedef struct {
HWVoiceOut hw;
LPDIRECTSOUNDBUFFER dsound_buffer;
+ bool first_time;
dsound *s;
} DSoundVoiceOut;
typedef struct {
HWVoiceIn hw;
LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
+ bool first_time;
dsound *s;
} DSoundVoiceIn;
@@ -414,21 +416,32 @@ static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
HRESULT hr;
- DWORD ppos, act_size;
+ DWORD ppos, wpos, act_size;
size_t req_size;
int err;
void *ret;
- hr = IDirectSoundBuffer_GetCurrentPosition(dsb, &ppos, NULL);
+ hr = IDirectSoundBuffer_GetCurrentPosition(
+ dsb, &ppos, ds->first_time ? &wpos : NULL);
if (FAILED(hr)) {
dsound_logerr(hr, "Could not get playback buffer position\n");
*size = 0;
return NULL;
}
+ if (ds->first_time) {
+ hw->pos_emul = wpos;
+ ds->first_time = false;
+ }
+
req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
+ if (req_size == 0) {
+ *size = 0;
+ return NULL;
+ }
+
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
&act_size, NULL, false, ds->s);
if (err) {
@@ -508,18 +521,24 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
HRESULT hr;
- DWORD cpos, act_size;
+ DWORD cpos, rpos, act_size;
size_t req_size;
int err;
void *ret;
- hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, &cpos, NULL);
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
+ dscb, &cpos, ds->first_time ? &rpos : NULL);
if (FAILED(hr)) {
dsound_logerr(hr, "Could not get capture buffer position\n");
*size = 0;
return NULL;
}
+ if (ds->first_time) {
+ hw->pos_emul = rpos;
+ ds->first_time = false;
+ }
+
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 2f5ba71..c14b0d8 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -267,6 +267,76 @@ f_sample *mixeng_clip[2][2][2][3] = {
}
};
+#ifdef FLOAT_MIXENG
+#define FLOAT_CONV_TO(x) (x)
+#define FLOAT_CONV_FROM(x) (x)
+#else
+static const float float_scale = UINT_MAX;
+#define FLOAT_CONV_TO(x) ((x) * float_scale)
+
+#ifdef RECIPROCAL
+static const float float_scale_reciprocal = 1.f / UINT_MAX;
+#define FLOAT_CONV_FROM(x) ((x) * float_scale_reciprocal)
+#else
+#define FLOAT_CONV_FROM(x) ((x) / float_scale)
+#endif
+#endif
+
+static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
+ int samples)
+{
+ float *in = (float *)src;
+
+ while (samples--) {
+ dst->r = dst->l = FLOAT_CONV_TO(*in++);
+ dst++;
+ }
+}
+
+static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
+ int samples)
+{
+ float *in = (float *)src;
+
+ while (samples--) {
+ dst->l = FLOAT_CONV_TO(*in++);
+ dst->r = FLOAT_CONV_TO(*in++);
+ dst++;
+ }
+}
+
+t_sample *mixeng_conv_float[2] = {
+ conv_natural_float_to_mono,
+ conv_natural_float_to_stereo,
+};
+
+static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
+ int samples)
+{
+ float *out = (float *)dst;
+
+ while (samples--) {
+ *out++ = FLOAT_CONV_FROM(src->l) + FLOAT_CONV_FROM(src->r);
+ src++;
+ }
+}
+
+static void clip_natural_float_from_stereo(
+ void *dst, const struct st_sample *src, int samples)
+{
+ float *out = (float *)dst;
+
+ while (samples--) {
+ *out++ = FLOAT_CONV_FROM(src->l);
+ *out++ = FLOAT_CONV_FROM(src->r);
+ src++;
+ }
+}
+
+f_sample *mixeng_clip_float[2] = {
+ clip_natural_float_from_mono,
+ clip_natural_float_from_stereo,
+};
void audio_sample_to_uint64(void *samples, int pos,
uint64_t *left, uint64_t *right)
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 18e62c7..2dcd6df 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -38,9 +38,14 @@ typedef struct st_sample st_sample;
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
+/* indices: [stereo][signed][swap endiannes][8, 16 or 32-bits] */
extern t_sample *mixeng_conv[2][2][2][3];
extern f_sample *mixeng_clip[2][2][2][3];
+/* indices: [stereo] */
+extern t_sample *mixeng_conv_float[2];
+extern f_sample *mixeng_clip_float[2];
+
void *st_rate_start (int inrate, int outrate);
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
size_t *isamp, size_t *osamp);
diff --git a/audio/noaudio.c b/audio/noaudio.c
index ff99b25..05798ea 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -118,6 +118,7 @@ static struct audio_pcm_ops no_pcm_ops = {
.init_out = no_init_out,
.fini_out = no_fini_out,
.write = no_write,
+ .run_buffer_out = audio_generic_run_buffer_out,
.enable_out = no_enable_out,
.init_in = no_init_in,
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index c43faee..f88d076 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -382,6 +382,15 @@ static size_t oss_get_available_bytes(OSSVoiceOut *oss)
return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
}
+static void oss_run_buffer_out(HWVoiceOut *hw)
+{
+ OSSVoiceOut *oss = (OSSVoiceOut *)hw;
+
+ if (!oss->mmapped) {
+ audio_generic_run_buffer_out(hw);
+ }
+}
+
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
@@ -420,7 +429,7 @@ static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len)
size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
- hw->pos_emul = (hw->pos_emul + to_copy) % hw->pos_emul;
+ hw->pos_emul = (hw->pos_emul + to_copy) % hw->size_emul;
buf += to_copy;
len -= to_copy;
}
@@ -570,20 +579,18 @@ static void oss_enable_out(HWVoiceOut *hw, bool enable)
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
if (enable) {
- bool poll_mode = opdo->try_poll;
+ hw->poll_mode = opdo->try_poll;
ldebug("enabling voice\n");
- if (poll_mode) {
+ if (hw->poll_mode) {
oss_poll_out(hw);
- poll_mode = 0;
}
- hw->poll_mode = poll_mode;
if (!oss->mmapped) {
return;
}
- audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->mix_buf->size);
+ audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples);
trig = PCM_ENABLE_OUTPUT;
if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr(errno,
@@ -699,17 +706,15 @@ static void oss_enable_in(HWVoiceIn *hw, bool enable)
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
if (enable) {
- bool poll_mode = opdo->try_poll;
+ hw->poll_mode = opdo->try_poll;
- if (poll_mode) {
+ if (hw->poll_mode) {
oss_poll_in(hw);
- poll_mode = 0;
}
- hw->poll_mode = poll_mode;
} else {
if (hw->poll_mode) {
- hw->poll_mode = 0;
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
+ hw->poll_mode = 0;
}
}
}
@@ -748,6 +753,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
.init_out = oss_init_out,
.fini_out = oss_fini_out,
.write = oss_write,
+ .run_buffer_out = oss_run_buffer_out,
.get_buffer_out = oss_get_buffer_out,
.put_buffer_out = oss_put_buffer_out,
.enable_out = oss_enable_out,
diff --git a/audio/paaudio.c b/audio/paaudio.c
index dbfe48c..b052084 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -32,7 +32,6 @@ typedef struct {
HWVoiceOut hw;
pa_stream *stream;
paaudio *g;
- size_t samples;
} PAVoiceOut;
typedef struct {
@@ -41,7 +40,6 @@ typedef struct {
const void *read_data;
size_t read_length;
paaudio *g;
- size_t samples;
} PAVoiceIn;
static void qpa_conn_fini(PAConnection *c);
@@ -279,6 +277,9 @@ static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
case AUDIO_FORMAT_U32:
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
break;
+ case AUDIO_FORMAT_F32:
+ format = endianness ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
+ break;
default:
dolog ("Internal logic error: Bad audio format %d\n", afmt);
format = PA_SAMPLE_U8;
@@ -304,6 +305,12 @@ static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
case PA_SAMPLE_S32LE:
*endianness = 0;
return AUDIO_FORMAT_S32;
+ case PA_SAMPLE_FLOAT32BE:
+ *endianness = 1;
+ return AUDIO_FORMAT_F32;
+ case PA_SAMPLE_FLOAT32LE:
+ *endianness = 0;
+ return AUDIO_FORMAT_F32;
default:
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
return AUDIO_FORMAT_U8;
@@ -488,7 +495,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
}
audio_pcm_init_info (&hw->info, &obt_as);
- hw->samples = pa->samples = audio_buffer_samples(
+ hw->samples = audio_buffer_samples(
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
&obt_as, ppdo->buffer_length);
@@ -536,7 +543,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
}
audio_pcm_init_info (&hw->info, &obt_as);
- hw->samples = pa->samples = audio_buffer_samples(
+ hw->samples = audio_buffer_samples(
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
&obt_as, ppdo->buffer_length);
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index 5c6bcfc..21b7a04 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -77,6 +77,14 @@ static int aud_to_sdlfmt (AudioFormat fmt)
case AUDIO_FORMAT_U16:
return AUDIO_U16LSB;
+ case AUDIO_FORMAT_S32:
+ return AUDIO_S32LSB;
+
+ /* no unsigned 32-bit support in SDL */
+
+ case AUDIO_FORMAT_F32:
+ return AUDIO_F32LSB;
+
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
@@ -119,6 +127,26 @@ static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness)
*fmt = AUDIO_FORMAT_U16;
break;
+ case AUDIO_S32LSB:
+ *endianness = 0;
+ *fmt = AUDIO_FORMAT_S32;
+ break;
+
+ case AUDIO_S32MSB:
+ *endianness = 1;
+ *fmt = AUDIO_FORMAT_S32;
+ break;
+
+ case AUDIO_F32LSB:
+ *endianness = 0;
+ *fmt = AUDIO_FORMAT_F32;
+ break;
+
+ case AUDIO_F32MSB:
+ *endianness = 1;
+ *fmt = AUDIO_FORMAT_F32;
+ break;
+
default:
dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
return -1;
@@ -227,7 +255,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
(hw, size), *size = 0, sdl_unlock)
-SDL_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
+SDL_WRAPPER_FUNC(put_buffer_out, size_t,
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
/*nothing*/, sdl_unlock_and_post)
SDL_WRAPPER_FUNC(write, size_t,
@@ -320,9 +348,12 @@ static void sdl_audio_fini (void *opaque)
static struct audio_pcm_ops sdl_pcm_ops = {
.init_out = sdl_init_out,
.fini_out = sdl_fini_out,
+ /* wrapper for audio_generic_write */
.write = sdl_write,
+ /* wrapper for audio_generic_get_buffer_out */
.get_buffer_out = sdl_get_buffer_out,
- .put_buffer_out = sdl_put_buffer_out_nowrite,
+ /* wrapper for audio_generic_put_buffer_out */
+ .put_buffer_out = sdl_put_buffer_out,
.enable_out = sdl_enable_out,
};
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index e46d834..20e6853 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -197,6 +197,7 @@ static struct audio_pcm_ops wav_pcm_ops = {
.init_out = wav_init_out,
.fini_out = wav_fini_out,
.write = wav_write_out,
+ .run_buffer_out = audio_generic_run_buffer_out,
.enable_out = wav_enable_out,
};
diff --git a/qapi/audio.json b/qapi/audio.json
index 83312b2..d8c507c 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -276,7 +276,7 @@
# Since: 4.0
##
{ 'enum': 'AudioFormat',
- 'data': [ 'u8', 's8', 'u16', 's16', 'u32', 's32' ] }
+ 'data': [ 'u8', 's8', 'u16', 's16', 'u32', 's32', 'f32' ] }
##
# @AudiodevDriver: