[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 14/25] audio: common rate control code for timer bas
From: |
Kővágó, Zoltán |
Subject: |
[Qemu-devel] [PATCH 14/25] audio: common rate control code for timer based outputs |
Date: |
Sun, 25 Aug 2019 20:46:16 +0200 |
This commit removes the ad-hoc rate-limiting code from noaudio and
wavaudio, and replaces them with a (slightly modified) code from
spiceaudio. This way multiple write calls (for example when the
circular buffer wraps around) do not cause problems.
Signed-off-by: Kővágó, Zoltán <address@hidden>
---
audio/audio_int.h | 9 +++++++++
audio/audio.c | 30 ++++++++++++++++++++++++++++
audio/noaudio.c | 49 +++++++++++++++++++++-------------------------
audio/spiceaudio.c | 49 +++++++---------------------------------------
audio/wavaudio.c | 21 ++++++++++----------
5 files changed, 78 insertions(+), 80 deletions(-)
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 65112b490a..573a84c6e4 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -243,6 +243,15 @@ void *audio_calloc (const char *funcname, int nmemb,
size_t size);
void audio_run(AudioState *s, const char *msg);
+typedef struct RateCtl {
+ int64_t start_ticks;
+ int64_t bytes_sent;
+} RateCtl;
+
+void audio_rate_start(RateCtl *rate);
+size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
+ size_t bytes_avail);
+
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
#define VOICE_VOLUME 3
diff --git a/audio/audio.c b/audio/audio.c
index 2b77a87823..2cec12fa54 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2044,3 +2044,33 @@ const char *audio_get_id(QEMUSoundCard *card)
return "";
}
}
+
+void audio_rate_start(RateCtl *rate)
+{
+ memset(rate, 0, sizeof(RateCtl));
+ rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
+ size_t bytes_avail)
+{
+ int64_t now;
+ int64_t ticks;
+ int64_t bytes;
+ int64_t samples;
+ size_t ret;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ticks = now - rate->start_ticks;
+ bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
+ samples = (bytes - rate->bytes_sent) >> info->shift;
+ if (samples < 0 || samples > 65536) {
+ AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)", samples);
+ audio_rate_start(rate);
+ samples = 0;
+ }
+
+ ret = MIN(samples << info->shift, bytes_avail);
+ rate->bytes_sent += ret;
+ return ret;
+}
diff --git a/audio/noaudio.c b/audio/noaudio.c
index f4b9d09d84..dc1078471a 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -33,32 +33,26 @@
typedef struct NoVoiceOut {
HWVoiceOut hw;
- int64_t old_ticks;
+ RateCtl rate;
} NoVoiceOut;
typedef struct NoVoiceIn {
HWVoiceIn hw;
- int64_t old_ticks;
+ RateCtl rate;
} NoVoiceIn;
static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
- int64_t now;
- int64_t ticks;
- int64_t bytes;
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ticks = now - no->old_ticks;
- bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
-
- no->old_ticks = now;
- return MIN(len, bytes);
+ return audio_rate_get_bytes(&hw->info, &no->rate, len);
}
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void
*drv_opaque)
{
+ NoVoiceOut *no = (NoVoiceOut *) hw;
+
audio_pcm_init_info (&hw->info, as);
+ audio_rate_start(&no->rate);
return 0;
}
@@ -69,14 +63,20 @@ static void no_fini_out (HWVoiceOut *hw)
static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
- (void) hw;
- (void) cmd;
+ NoVoiceOut *no = (NoVoiceOut *) hw;
+
+ if (cmd == VOICE_ENABLE) {
+ audio_rate_start(&no->rate);
+ }
return 0;
}
static int no_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
+ NoVoiceIn *no = (NoVoiceIn *) hw;
+
audio_pcm_init_info (&hw->info, as);
+ audio_rate_start(&no->rate);
return 0;
}
@@ -87,25 +87,20 @@ static void no_fini_in (HWVoiceIn *hw)
static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
{
- size_t to_clear;
NoVoiceIn *no = (NoVoiceIn *) hw;
+ int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size);
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int64_t ticks = now - no->old_ticks;
- int64_t bytes =
- muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
-
- no->old_ticks = now;
- to_clear = MIN(bytes, size);
-
- audio_pcm_info_clear_buf(&hw->info, buf, to_clear >> hw->info.shift);
- return to_clear;
+ audio_pcm_info_clear_buf(&hw->info, buf, bytes >> hw->info.shift);
+ return bytes;
}
static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
- (void) hw;
- (void) cmd;
+ NoVoiceIn *no = (NoVoiceIn *) hw;
+
+ if (cmd == VOICE_ENABLE) {
+ audio_rate_start(&no->rate);
+ }
return 0;
}
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 02e97095fc..a6b875ac36 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -40,15 +40,10 @@
#define LINE_IN_SAMPLES (256 * 4)
#endif
-typedef struct SpiceRateCtl {
- int64_t start_ticks;
- int64_t bytes_sent;
-} SpiceRateCtl;
-
typedef struct SpiceVoiceOut {
HWVoiceOut hw;
SpicePlaybackInstance sin;
- SpiceRateCtl rate;
+ RateCtl rate;
int active;
uint32_t *frame;
uint32_t fpos;
@@ -58,7 +53,7 @@ typedef struct SpiceVoiceOut {
typedef struct SpiceVoiceIn {
HWVoiceIn hw;
SpiceRecordInstance sin;
- SpiceRateCtl rate;
+ RateCtl rate;
int active;
} SpiceVoiceIn;
@@ -89,32 +84,6 @@ static void spice_audio_fini (void *opaque)
/* nothing */
}
-static void rate_start (SpiceRateCtl *rate)
-{
- memset (rate, 0, sizeof (*rate));
- rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-
-static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
-{
- int64_t now;
- int64_t ticks;
- int64_t bytes;
- int64_t samples;
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ticks = now - rate->start_ticks;
- bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
- samples = (bytes - rate->bytes_sent) >> info->shift;
- if (samples < 0 || samples > 65536) {
- error_report("Resetting rate control (%" PRId64 " samples)", samples);
- rate_start(rate);
- samples = 0;
- }
- rate->bytes_sent += samples << info->shift;
- return samples;
-}
-
/* playback */
static int line_out_init(HWVoiceOut *hw, struct audsettings *as,
@@ -158,17 +127,14 @@ static void line_out_fini (HWVoiceOut *hw)
static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
{
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
- size_t decr;
if (!out->frame) {
spice_server_playback_get_buffer(&out->sin, &out->frame, &out->fsize);
out->fpos = 0;
}
- decr = rate_get_samples(&hw->info, &out->rate);
- decr = MIN(out->fsize - out->fpos, decr);
-
- *size = decr << hw->info.shift;
+ *size = audio_rate_get_bytes(&hw->info, &out->rate,
+ (out->fsize - out->fpos) << hw->info.shift);
return out->frame + out->fpos;
}
@@ -197,7 +163,7 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
break;
}
out->active = 1;
- rate_start (&out->rate);
+ audio_rate_start(&out->rate);
spice_server_playback_start (&out->sin);
break;
case VOICE_DISABLE:
@@ -277,8 +243,7 @@ static void line_in_fini (HWVoiceIn *hw)
static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
- uint64_t delta_samp = rate_get_samples(&hw->info, &in->rate);
- uint64_t to_read = MIN(len >> 2, delta_samp);
+ uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2;
size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read);
/* XXX: do we need this? */
@@ -300,7 +265,7 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
break;
}
in->active = 1;
- rate_start (&in->rate);
+ audio_rate_start(&in->rate);
spice_server_record_start (&in->sin);
break;
case VOICE_DISABLE:
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 427825c8d8..9b3bd086ae 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -35,21 +35,15 @@
typedef struct WAVVoiceOut {
HWVoiceOut hw;
FILE *f;
- int64_t old_ticks;
+ RateCtl rate;
int total_samples;
} WAVVoiceOut;
static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int64_t ticks = now - wav->old_ticks;
- int64_t bytes =
- muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
-
- bytes = MIN(bytes, len);
- bytes = bytes >> hw->info.shift << hw->info.shift;
- wav->old_ticks = now;
+ int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len);
+ assert(bytes >> hw->info.shift << hw->info.shift == bytes);
if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) {
dolog("wav_write_out: fwrite of %zu bytes failed\nReaons: %s\n",
@@ -129,6 +123,8 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings
*as,
strerror(errno));
return -1;
}
+
+ audio_rate_start(&wav->rate);
return 0;
}
@@ -178,8 +174,11 @@ static void wav_fini_out (HWVoiceOut *hw)
static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
- (void) hw;
- (void) cmd;
+ WAVVoiceOut *wav = (WAVVoiceOut *) hw;
+
+ if (cmd == VOICE_ENABLE) {
+ audio_rate_start(&wav->rate);
+ }
return 0;
}
--
2.22.0
- [Qemu-devel] [PATCH 10/25] wavaudio: port to the new audio backend api, (continued)
- [Qemu-devel] [PATCH 10/25] wavaudio: port to the new audio backend api, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 07/25] paaudio: port to the new audio backend api, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 11/25] audio: remove remains of the old backend api, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 13/25] audio: remove hw->samples, buffer_size_in/out pcm_ops, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 16/25] audio: add mixeng option (documentation), Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 17/25] audio: make mixeng optional, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 12/25] audio: unify input and output mixeng buffer management, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 14/25] audio: common rate control code for timer based outputs,
Kővágó, Zoltán <=
- [Qemu-devel] [PATCH 15/25] audio: split ctl_* functions into enable_* and volume_*, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 19/25] audio: support more than two channels in volume setting, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 21/25] audio: basic support for multichannel audio, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 23/25] usb-audio: do not count on avail bytes actually available, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 20/25] audio: replace shift in audio_pcm_info with bytes_per_frame, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 25/25] usbaudio: change playback counters to 64 bit, Kővágó, Zoltán, 2019/08/25
- [Qemu-devel] [PATCH 22/25] paaudio: channel-map option, Kővágó, Zoltán, 2019/08/25