diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-02-07 13:42:09 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-02-07 13:42:09 +0000 |
commit | b6bef1147f0f4edb7d8aac1e26d9511898ae854d (patch) | |
tree | ccacabee62a6fab86ec0a92386eba3fee33fb849 | |
parent | 346ed3151f1c43e72c40cb55b392a1d4cface62c (diff) | |
parent | ed2a4a794184df3dbd5ee4cc06e86fe220663faf (diff) | |
download | qemu-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.c | 18 | ||||
-rw-r--r-- | audio/audio.c | 139 | ||||
-rw-r--r-- | audio/audio_int.h | 7 | ||||
-rw-r--r-- | audio/audio_template.h | 40 | ||||
-rw-r--r-- | audio/coreaudio.c | 34 | ||||
-rw-r--r-- | audio/dsound_template.h | 1 | ||||
-rw-r--r-- | audio/dsoundaudio.c | 27 | ||||
-rw-r--r-- | audio/mixeng.c | 70 | ||||
-rw-r--r-- | audio/mixeng.h | 5 | ||||
-rw-r--r-- | audio/noaudio.c | 1 | ||||
-rw-r--r-- | audio/ossaudio.c | 28 | ||||
-rw-r--r-- | audio/paaudio.c | 15 | ||||
-rw-r--r-- | audio/sdlaudio.c | 35 | ||||
-rw-r--r-- | audio/wavaudio.c | 1 | ||||
-rw-r--r-- | qapi/audio.json | 2 |
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: |