From patchwork Fri Aug 21 15:37:44 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?UTF-8?B?Wm9sdMOhbiBLxZF2w6Fnw7M=?= X-Patchwork-Id: 509574 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id F01ED1402C8 for ; Sat, 22 Aug 2015 02:10:16 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=QDEs00Hi; dkim-atps=neutral Received: from localhost ([::1]:42432 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZSotS-0008VU-Lr for incoming@patchwork.ozlabs.org; Fri, 21 Aug 2015 12:10:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:51171) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZSoOa-00035l-Uk for qemu-devel@nongnu.org; Fri, 21 Aug 2015 11:38:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZSoOY-0002Fx-3K for qemu-devel@nongnu.org; Fri, 21 Aug 2015 11:38:20 -0400 Received: from mail-wi0-x22e.google.com ([2a00:1450:400c:c05::22e]:38682) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZSoOX-0002FS-Pv for qemu-devel@nongnu.org; Fri, 21 Aug 2015 11:38:18 -0400 Received: by wicja10 with SMTP id ja10so19179610wic.1 for ; Fri, 21 Aug 2015 08:38:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=8Zc6Z4e+FBcyolG0tEPpsCyiowUoZdeRCdfevYBirs8=; b=QDEs00HiE/AT4cYQvbOirVWB6qghUoDS3RDcGn1X1lYct7NHacozHqdFZk9iOJHETp byvhqhhyY/HJQs/ZhloeW2eKYx1MFtyXKsmRfxUJne4wGQSb3SpZ4LGmLfCVNoPU+B7N +sQASh60w7Huruf6SQJYV8T55URNVm6QqtNdWTuL1pu1+ufRoqGoVzdtPdUK7u2T3Ek8 YPbkJ4Iy6WjA/NKGPAiwt1EZaYcrYf4P4GKCxmYs3Le9Gl2VksgOh771111ierScQLxk mLB0+pfk6SBGh/tMTb/3spPrIUnZCZxRUE2Wy5zUqjBZhj+fnkv/Nooi7wLTtKksM8d5 8AGg== X-Received: by 10.180.99.39 with SMTP id en7mr6494690wib.49.1440171497166; Fri, 21 Aug 2015 08:38:17 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (178-164-172-216.pool.digikabel.hu. [178.164.172.216]) by smtp.gmail.com with ESMTPSA id v8sm10479895wjr.15.2015.08.21.08.38.16 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 21 Aug 2015 08:38:16 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?= To: qemu-devel@nongnu.org Date: Fri, 21 Aug 2015 17:37:44 +0200 Message-Id: X-Mailer: git-send-email 2.5.0 In-Reply-To: References: MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c05::22e Cc: Gerd Hoffmann Subject: [Qemu-devel] [PATCH v2 48/49] audio: common rate control code for timer based outputs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- audio/audio.c | 30 ++++++++++++++++++++++++++++++ audio/audio_int.h | 9 +++++++++ audio/noaudio.c | 49 ++++++++++++++++++++++--------------------------- audio/spiceaudio.c | 49 +++++++------------------------------------------ audio/wavaudio.c | 20 ++++++++++---------- 5 files changed, 78 insertions(+), 79 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 4ae91e4..935fd0d 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1958,3 +1958,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, get_ticks_per_sec()); + 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/audio_int.h b/audio/audio_int.h index 1250012..16ffa12 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -238,6 +238,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/noaudio.c b/audio/noaudio.c index 6c73a48..3cb3a89 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -30,32 +30,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, get_ticks_per_sec ()); - - 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; } @@ -66,14 +60,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; } @@ -84,25 +84,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, get_ticks_per_sec ()); - - 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 97ab0b3..c8759fc 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -38,15 +38,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; @@ -56,7 +51,7 @@ typedef struct SpiceVoiceOut { typedef struct SpiceVoiceIn { HWVoiceIn hw; SpiceRecordInstance sin; - SpiceRateCtl rate; + RateCtl rate; int active; } SpiceVoiceIn; @@ -87,32 +82,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, get_ticks_per_sec ()); - 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, @@ -156,17 +125,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; } @@ -195,7 +161,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: @@ -275,8 +241,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? */ @@ -298,7 +263,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 437ce1b..14afaaf 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -32,20 +32,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, get_ticks_per_sec ()); - 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", @@ -125,6 +120,8 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as, strerror(errno)); return -1; } + + audio_rate_start(&wav->rate); return 0; } @@ -174,8 +171,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; }